From 7e60fc2495fd2c19ee2f1a4d24c6f0fef57d680f Mon Sep 17 00:00:00 2001 From: Ivan Yakubenko Date: Thu, 8 Jan 2026 12:10:06 +0200 Subject: [PATCH 1/4] Move quanthub jsdmx libs to opensource and update java to 17 --- .github/workflows/ci.yml | 2 +- .github/workflows/release.yml | 4 +- build.gradle | 4 +- gradle.properties | 23 +- gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 43764 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- sdmx-json10/build.gradle | 49 + .../structure/writer/AgencySchemeWriter.java | 42 + .../structure/writer/AnnotableWriter.java | 44 + .../structure/writer/AttributeListWriter.java | 111 + .../structure/writer/BaseWriterJson.java | 20 + .../writer/CategorisationWriter.java | 53 + .../writer/CategorySchemeWriter.java | 56 + .../json10/structure/writer/CodeWriter.java | 43 + .../structure/writer/CodeWriterImpl.java | 6 + .../structure/writer/CodelistWriter.java | 50 + .../structure/writer/ComponentWriter.java | 37 + .../structure/writer/ConceptRoleWriter.java | 27 + .../structure/writer/ConceptSchemeWriter.java | 59 + .../structure/writer/ContactsWriter.java | 76 + .../writer/ContentConstraintWriter.java | 136 + .../structure/writer/CubeRegionWriter.java | 69 + .../structure/writer/DataKeySetsWriter.java | 67 + .../writer/DataStructureComponentsUtils.java | 34 + .../writer/DataStructureDefinitionWriter.java | 86 + .../structure/writer/DataflowWriter.java | 41 + .../writer/DefaultHeaderProvider.java | 44 + .../structure/writer/DimensionListWriter.java | 95 + .../writer/GroupDimensionListWriter.java | 40 + .../writer/HierarchicalCodelistWriter.java | 128 + .../structure/writer/IdentifiableWriter.java | 26 + .../writer/Json10StructureWriter.java | 88 + .../structure/writer/Json10WriterFactory.java | 136 + .../writer/JsonRuntimeException.java | 8 + .../json10/structure/writer/LinksWriter.java | 49 + .../structure/writer/MaintainableWriter.java | 60 + .../structure/writer/MeasureListWriter.java | 59 + .../json10/structure/writer/MetaWriter.java | 66 + .../writer/MetadataConstraintWriter.java | 53 + .../structure/writer/NameableWriter.java | 39 + .../structure/writer/OrganisationWriter.java | 57 + .../writer/RepresentationWriter.java | 56 + .../writer/SelectionValueWriter.java | 106 + .../structure/writer/StructureUtils.java | 297 + .../structure/writer/VersionableWriter.java | 32 + .../MaintainableArtifactsTestUtils.java | 1061 ++++ .../SdmxSourceCompatibilityTester.java | 57 + .../jsdmx/json10/structure/TestUtils.java | 23 + .../writer/AttributeListWriterJsonTest.java | 90 + .../writer/CategorisationWriterTest.java | 45 + .../writer/CategorySchemeWriterTest.java | 44 + .../structure/writer/CodelistWriterTest.java | 43 + .../writer/ConceptSchemeWriterTest.java | 44 + .../writer/ContentConstraintWriterTest.java | 65 + .../DataStructureDefinitionWriterTest.java | 71 + .../structure/writer/DataflowWriterTest.java | 53 + .../writer/DimensionListWriterJsonTest.java | 90 + .../json10/structure/writer/GenericTest.java | 53 + .../GroupDimensionListWriterJsonTest.java | 59 + .../HierarchicalCodelistWriterTest.java | 67 + .../writer/Json10StructureWriterTest.java | 210 + .../structure/writer/JsonWriterTestBase.java | 68 + .../writer/MeasureListWriterJsonTest.java | 86 + .../category-schema2.json | 37 + .../codelist_wild.json | 89 + .../concept-schema.json | 66 + .../deserialization.expected/data-flow.json | 41 + .../data-structure-definition-attr.json | 94 + ...ta-structure-definition-attr_and_null.json | 94 + .../data-structure-definition-attr_null.json | 94 + ...structure-definition-components_empty.json | 41 + ...-structure-definition-components_null.json | 41 + .../data-structure-definition-dim.json | 73 + ...ata-structure-definition-dim_and_null.json | 73 + .../data-structure-definition-dim_null.json | 115 + .../data-structure-definition-full.json | 147 + .../data-structure-definition-meas.json | 62 + ...ta-structure-definition-meas_and_null.json | 62 + .../data-structure-definition-meas_null.json | 126 + .../deserialization.expected/hierarchy.json | 88 + .../deserialization.expected/json.json | 158 + .../metadata-all-artefacts.json | 74 + .../structure-maps-full.json | 119 + .../structure-maps-list-full.json | 201 + .../structures-all-artefacts.json | 811 +++ .../deserialization.expected/test.json | 147 + .../serialization.expected/agency-scheme.json | 148 + .../attribute-list.json | 26 + .../attribute-list_empty.json | 3 + .../categorisation.json | 36 + .../category-schema.json | 92 + .../category-scheme-map.json | 60 + .../serialization.expected/codelist.json | 60 + .../concept-scheme-map.json | 60 + .../concept-scheme.json | 49 + .../data-constraint.json | 99 + .../data-consumer-scheme.json | 90 + .../serialization.expected/data-flow.json | 40 + .../data-provider-scheme.json | 92 + .../data-structure-definition-order.json | 147 + .../data-structure-definition.json | 113 + .../dimension-list.json | 27 + .../dimension-list_empty.json | 3 + .../empty-structure.json | 15 + .../expected-flat-json-streamer-response.json | 110 + .../serialization.expected/geocodelist.json | 92 + .../geogridcodelist.json | 93 + .../group-dimension-list.json | 26 + .../serialization.expected/hierarchy.json | 87 + .../hierarchy_flat.json | 77 + .../serialization.expected/measure-list.json | 14 + .../measure-list_empty.json | 3 + .../meta-data-constraint.json | 69 + .../metadata-constraint.json | 77 + .../serialization.expected/metadata-flow.json | 39 + .../metadata-provider-scheme.json | 96 + .../metadata-provision-agreement.json | 37 + .../metadata-structure-definition.json | 68 + .../serialization.expected/metadata.json | 75 + .../serialization.expected/metadataset.json | 56 + .../organisation-scheme-map.json | 60 + .../organisation-unit-scheme.json | 103 + .../serialization.expected/process.json | 136 + .../provision-agreement.json | 37 + .../reporting-taxonomy-map.json | 69 + .../reporting-taxonomy.json | 88 + .../representation-map.json | 67 + .../structure-map-with-null-map.json | 65 + ...structure-map-with-null-target-source.json | 120 + .../serialization.expected/structure-map.json | 116 + .../serialization.expected/structure.json | 148 + .../serialization.expected/valuelist.json | 79 + sdmx-json20/build.gradle | 47 + .../structure/reader/AgencySchemeReader.java | 65 + .../structure/reader/AnnotableReader.java | 153 + .../structure/reader/AttributeListReader.java | 200 + .../reader/CategorisationReader.java | 68 + .../reader/CategorySchemeMapReader.java | 56 + .../reader/CategorySchemeReader.java | 80 + .../structure/reader/CodeImplReader.java | 6 + .../json20/structure/reader/CodeReader.java | 49 + .../reader/CodelistExtensionReader.java | 188 + .../structure/reader/CodelistReader.java | 88 + .../structure/reader/ConceptRoleUtils.java | 33 + .../reader/ConceptSchemeMapReader.java | 56 + .../structure/reader/ConceptSchemeReader.java | 127 + .../structure/reader/ContactReader.java | 109 + .../structure/reader/CubeRegionReader.java | 133 + .../reader/DataConstraintReader.java | 124 + .../reader/DataConsumerSchemeReader.java | 77 + .../structure/reader/DataFlowReader.java | 44 + .../structure/reader/DataKeySetReader.java | 164 + .../reader/DataProviderSchemeReader.java | 77 + .../json20/structure/reader/DataReader.java | 93 + .../reader/DataStructureDefinitionReader.java | 89 + .../structure/reader/DimensionListReader.java | 145 + .../reader/GeoFeatureSetCodeReader.java | 18 + .../reader/GeoGridCodelistReader.java | 95 + .../reader/GeographicCodelistReader.java | 93 + .../structure/reader/GridCodeReader.java | 19 + .../reader/HierarchyAssociationReader.java | 60 + .../structure/reader/HierarchyReader.java | 229 + .../structure/reader/IdentifiableReader.java | 29 + .../structure/reader/ItemMapReader.java | 59 + .../structure/reader/JsonReaderFactory.java | 254 + .../reader/JsonRuntimeException.java | 11 + .../structure/reader/JsonStructureReader.java | 78 + .../structure/reader/MaintainableReader.java | 82 + .../structure/reader/MeasureListReader.java | 88 + .../reader/MemberSelectionReader.java | 196 + .../MetaDataStructureDefinitionReader.java | 148 + .../json20/structure/reader/MetaReader.java | 107 + .../reader/MetadataConstraintReader.java | 153 + .../structure/reader/MetadataFlowReader.java | 70 + .../reader/MetadataProviderSchemeReader.java | 64 + .../MetadataProvisionAgreementReader.java | 55 + .../structure/reader/NameableReader.java | 48 + .../structure/reader/OrganisationReader.java | 83 + .../reader/OrganisationSchemeMapReader.java | 56 + .../reader/OrganisationUnitSchemeReader.java | 79 + .../structure/reader/ProcessReader.java | 260 + .../reader/ProvisionAgreementReader.java | 55 + .../json20/structure/reader/ReaderUtils.java | 191 + .../reader/ReleaseCalendarReader.java | 35 + .../reader/ReportingTaxonomyMapReader.java | 56 + .../reader/ReportingTaxonomyReader.java | 99 + .../reader/RepresentationMapReader.java | 230 + .../reader/RepresentationReader.java | 196 + .../structure/reader/StructureMapReader.java | 432 ++ .../structure/reader/ValueListReader.java | 98 + .../structure/reader/VersionableReader.java | 41 + .../structure/writer/AgencySchemeWriter.java | 42 + .../structure/writer/AnnotableWriter.java | 72 + .../structure/writer/AttributeListWriter.java | 123 + .../structure/writer/BaseWriterJson.java | 20 + .../writer/CategorisationWriter.java | 47 + .../writer/CategorySchemeMapWriter.java | 44 + .../writer/CategorySchemeWriter.java | 56 + .../json20/structure/writer/CodeWriter.java | 43 + .../structure/writer/CodeWriterImpl.java | 6 + .../writer/CodelistExtensionWriter.java | 110 + .../structure/writer/CodelistWriter.java | 57 + .../structure/writer/ComponentWriter.java | 33 + .../structure/writer/ConceptRoleWriter.java | 29 + .../writer/ConceptSchemeMapWriter.java | 45 + .../structure/writer/ConceptSchemeWriter.java | 85 + .../structure/writer/ContactsWriter.java | 76 + .../structure/writer/CubeRegionWriter.java | 60 + .../writer/DataConstraintWriter.java | 115 + .../writer/DataConsumerSchemeWriter.java | 47 + .../structure/writer/DataKeySetsWriter.java | 90 + .../writer/DataProviderSchemeWriter.java | 44 + .../writer/DataStructureComponentsUtils.java | 34 + .../writer/DataStructureDefinitionWriter.java | 88 + .../structure/writer/DataflowWriter.java | 39 + .../structure/writer/DateTimeWriter.java | 78 + .../structure/writer/DimensionListWriter.java | 92 + .../writer/GeoFeatureSetCodeWriter.java | 19 + .../writer/GeoGridCodelistWriter.java | 52 + .../writer/GeographicCodelistWriter.java | 58 + .../structure/writer/GridCodeWriter.java | 18 + .../writer/GroupDimensionListWriter.java | 40 + .../writer/HierarchyAssociationWriter.java | 48 + .../structure/writer/HierarchyWriter.java | 110 + .../structure/writer/IdentifiableWriter.java | 26 + .../structure/writer/ItemMapWriter.java | 95 + .../structure/writer/JsonStructureWriter.java | 137 + .../structure/writer/JsonWriterFactory.java | 378 ++ .../json20/structure/writer/LinksWriter.java | 34 + .../structure/writer/MaintainableWriter.java | 60 + .../structure/writer/MappedComponent.java | 13 + .../structure/writer/MeasureListWriter.java | 59 + .../writer/MemberSelectionWriter.java | 92 + .../json20/structure/writer/MetaWriter.java | 78 + .../writer/MetadataConstraintWriter.java | 147 + .../writer/MetadataProviderSchemeWriter.java | 38 + .../MetadataProvisionAgreementWriter.java | 48 + .../MetadataStructureDefinitionWriter.java | 77 + .../structure/writer/MetadataflowWriter.java | 74 + .../structure/writer/NameableWriter.java | 54 + .../writer/OrganisationSchemeMapWriter.java | 45 + .../writer/OrganisationUnitSchemeWriter.java | 45 + .../structure/writer/OrganisationWriter.java | 59 + .../structure/writer/ProcessWriter.java | 172 + .../writer/ProvisionAgreementWriter.java | 46 + .../writer/ReportingTaxonomyMapWriter.java | 45 + .../writer/ReportingTaxonomyWriter.java | 73 + .../writer/RepresentationMapWriter.java | 140 + .../writer/RepresentationWriter.java | 112 + .../structure/writer/StructureMapUtils.java | 147 + .../structure/writer/StructureMapWriter.java | 255 + .../structure/writer/StructureUtils.java | 446 ++ .../structure/writer/ValueListWriter.java | 83 + .../structure/writer/VersionableWriter.java | 29 + .../MaintainableArtifactsTestUtils.java | 1776 ++++++ .../jsdmx/json20/structure/TestUtils.java | 40 + .../structure/reader/ArtefactAssertion.java | 91 + .../structure/reader/BaseJsonReaderTest.java | 128 + .../reader/CategorisationReaderTest.java | 33 + .../reader/CategorySchemeReaderTest.java | 54 + .../structure/reader/CodelistReaderTest.java | 51 + .../reader/ConceptSchemeReaderTest.java | 54 + .../reader/DataConstraintReaderTest.java | 53 + .../structure/reader/DataReaderTest.java | 138 + .../DataStructureDefinitionReaderTest.java | 278 + .../structure/reader/HierarchyReaderTest.java | 58 + .../reader/MetadataFlowReaderTest.java | 49 + ...MetadataStructureDefinitionReaderTest.java | 44 + .../reader/RepresentationMapReaderTest.java | 32 + .../reader/StructureMapReaderTest.java | 128 + .../writer/AttributeListWriterJsonTest.java | 82 + .../structure/writer/BaseJsonWriterTest.java | 185 + .../writer/CategorisationWriterTest.java | 39 + .../writer/CategorySchemeWriterTest.java | 38 + .../structure/writer/CodelistWriterTest.java | 38 + .../writer/ConceptSchemeWriterTest.java | 39 + .../writer/DataConstraintWriterTest.java | 64 + .../DataStructureDefinitionWriterTest.java | 46 + .../writer/DimensionListWriterJsonTest.java | 82 + .../GroupDimensionListWriterJsonTest.java | 60 + .../structure/writer/HierarchyWriterTest.java | 55 + .../writer/JsonStructureWriterTest.java | 209 + .../writer/MeasureListWriterJsonTest.java | 78 + ...MetaDataStructureDefinitionWriterTest.java | 40 + .../writer/MetadataflowWriterTest.java | 68 + .../writer/RepresentationMapWriterTest.java | 38 + .../writer/StructureMapWriterTest.java | 90 + .../category-schema2.json | 30 + .../codelist_wild.json | 82 + .../concept-schema.json | 59 + .../deserialization.expected/data-flow.json | 34 + .../data-structure-definition-attr.json | 87 + ...ta-structure-definition-attr_and_null.json | 87 + .../data-structure-definition-attr_null.json | 87 + ...structure-definition-components_empty.json | 34 + ...-structure-definition-components_null.json | 34 + .../data-structure-definition-dim.json | 66 + ...ata-structure-definition-dim_and_null.json | 66 + .../data-structure-definition-dim_null.json | 108 + .../data-structure-definition-full.json | 140 + .../data-structure-definition-meas.json | 55 + ...ta-structure-definition-meas_and_null.json | 55 + .../data-structure-definition-meas_null.json | 119 + .../deserialization.expected/hierarchy.json | 74 + .../deserialization.expected/hierarchy2.json | 58 + .../deserialization.expected/json.json | 144 + .../metadata-all-artefacts.json | 67 + .../structure-maps-full.json | 112 + .../structure-maps-list-full.json | 187 + .../structures-all-artefacts.json | 886 +++ .../deserialization.expected/test.json | 147 + .../serialization.expected/agency-scheme.json | 141 + .../attribute-list.json | 55 + .../attribute-list_empty.json | 1 + .../categorisation.json | 28 + .../category-schema.json | 86 + .../category-scheme-map.json | 52 + .../serialization.expected/codelist.json | 80 + .../concept-scheme-enumerated-concept.json | 92 + .../concept-scheme-map.json | 52 + .../concept-scheme.json | 60 + .../data-constraint-empty.json | 31 + .../data-constraint.json | 137 + .../data-consumer-scheme.json | 83 + .../serialization.expected/data-flow.json | 32 + .../data-provider-scheme.json | 84 + .../data-structure-definition-order.json | 138 + .../data-structure-definition.json | 27 + .../dimension-list.json | 30 + .../dimension-list_empty.json | 1 + .../empty-structure.json | 15 + .../expected-flat-json-streamer-response.json | 110 + .../serialization.expected/geocodelist.json | 83 + .../geogridcodelist.json | 84 + .../group-dimension-list.json | 29 + .../hierarchy-association.json | 29 + .../serialization.expected/hierarchy.json | 64 + .../serialization.expected/measure-list.json | 24 + .../measure-list_empty.json | 1 + .../metadata-constraint.json | 68 + .../serialization.expected/metadata-flow.json | 31 + .../metadata-provider-scheme.json | 84 + .../metadata-provision-agreement.json | 28 + ...structure-definition-multi-attributes.json | 58 + .../metadata-structure-definition.json | 62 + .../serialization.expected/metadata.json | 66 + .../serialization.expected/metadataset.json | 47 + .../organisation-scheme-map.json | 52 + .../organisation-unit-scheme.json | 96 + .../serialization.expected/process.json | 107 + .../provision-agreement.json | 28 + .../reporting-taxonomy-map.json | 52 + .../reporting-taxonomy.json | 71 + .../representation-map.json | 58 + .../structure-map-with-null-map.json | 56 + ...structure-map-with-null-target-source.json | 111 + .../serialization.expected/structure-map.json | 107 + .../serialization.expected/structure.json | 110 + .../serialization.expected/valuelist.json | 62 + sdmx-ml21/build.gradle | 50 + .../structure/writer/AnnotableWriter.java | 56 + .../structure/writer/AttributeListWriter.java | 128 + .../writer/CategorisationWriter.java | 62 + .../writer/CategorySchemeWriter.java | 64 + .../xml21/structure/writer/CodeWriter.java | 59 + .../structure/writer/CodeWriterImpl.java | 11 + .../structure/writer/CodelistWriter.java | 62 + .../writer/CommonAttributesWriter.java | 73 + .../structure/writer/ConceptSchemeWriter.java | 104 + .../xml21/structure/writer/ContactWriter.java | 57 + .../writer/ContentConstraintWriter.java | 150 + .../structure/writer/CubeRegionWriter.java | 55 + .../structure/writer/DataKeySetsWriter.java | 72 + .../writer/DataStructureDefinitionWriter.java | 79 + .../structure/writer/DataflowWriter.java | 53 + .../structure/writer/DimensionListWriter.java | 106 + .../writer/GroupDimensionListWriter.java | 40 + .../xml21/structure/writer/HeaderWriter.java | 77 + .../writer/HierarchicalCodelistWriter.java | 320 ++ .../structure/writer/ItemSchemeMapWriter.java | 46 + .../structure/writer/MeasureListWriter.java | 73 + .../writer/MemberSelectionWriter.java | 118 + .../writer/MetadataConstraintWriter.java | 38 + .../structure/writer/NameableWriter.java | 19 + .../writer/OrganisationSchemeWriter.java | 124 + .../structure/writer/OrganisationWriter.java | 66 + .../structure/writer/ReferenceWriter.java | 201 + .../writer/ReleaseCalenderWriter.java | 36 + .../writer/RepresentationWriter.java | 172 + .../writer/Xml21StructureWriter.java | 92 + .../structure/writer/Xml21WriterFactory.java | 155 + .../xml21/structure/writer/XmlConstants.java | 355 ++ .../xml21/structure/writer/XmlWriter.java | 60 + .../structure/writer/XmlWriterUtils.java | 142 + .../MaintainableArtifactsTestUtils.java | 1411 +++++ .../SdmxSourceCompatibilityTester.java | 26 + .../epam/jsdmx/xml21/structure/TestUtils.java | 48 + .../structure/writer/BaseXmlWriterTest.java | 159 + .../writer/CategorisationWriterTest.java | 109 + .../writer/CategorySchemeWriterTest.java | 53 + .../structure/writer/CodelistWriterTest.java | 57 + .../writer/ConceptSchemeWriterTest.java | 57 + .../writer/ContentConstraintWriterTest.java | 93 + .../writer/DataConsumerSchemeWriterTest.java | 57 + .../writer/DataProviderSchemeWriterTest.java | 57 + .../DataStructureDefinitionWriterTest.java | 63 + .../structure/writer/DataflowWriterTest.java | 56 + .../HierarchicalCodelistWriterTest.java | 90 + .../writer/OrganisationSchemeWriterTest.java | 55 + .../writer/Xml21StructureWriterTest.java | 101 + .../xml21/structure/writer/XsdToXmlTest.java | 49 + .../src/test/resources/xml/agency-scheme.xml | 86 + sdmx-ml21/src/test/resources/xml/all.xml | 212 + .../src/test/resources/xml/categorisation.xml | 42 + .../xml/categorisation_with_hierarchy_ref.xml | 42 + .../resources/xml/category-scheme-map.xml | 51 + .../test/resources/xml/category-scheme.xml | 57 + sdmx-ml21/src/test/resources/xml/codelist.xml | 46 + .../test/resources/xml/concept-scheme-map.xml | 51 + .../src/test/resources/xml/concept-scheme.xml | 47 + .../test/resources/xml/data-constraints.xml | 70 + .../resources/xml/data-consumer-scheme.xml | 59 + .../resources/xml/data-provider-scheme.xml | 63 + sdmx-ml21/src/test/resources/xml/dataflow.xml | 40 + sdmx-ml21/src/test/resources/xml/dsd.xml | 127 + .../resources/xml/geographical-codelist.xml | 56 + .../test/resources/xml/geogrid-codelist.xml | 58 + .../src/test/resources/xml/hierarchy.xml | 67 + .../test/resources/xml/hierarchy_names.xml | 69 + .../resources/xml/metadata-constraints.xml | 53 + .../xml/metadata-provider-scheme.xml | 63 + .../xml/metadata-provision-agreement.xml | 37 + .../resources/xml/organisation-scheme-map.xml | 51 + .../xml/organisation-unit-scheme.xml | 64 + sdmx-ml21/src/test/resources/xml/process.xml | 70 + .../resources/xml/provision-agreement.xml | 36 + .../resources/xml/reporting-taxonomy-map.xml | 51 + .../test/resources/xml/reporting-taxonomy.xml | 61 + .../test/resources/xml/representation_map.xml | 42 + .../src/test/resources/xml/structure_map.xml | 70 + .../src/test/resources/xml/valuelist.xml | 50 + .../resources/xml/xsd/schemas/SDMXCommon.xsd | 1733 ++++++ .../xml/xsd/schemas/SDMXCommonReferences.xsd | 4951 +++++++++++++++++ .../xml/xsd/schemas/SDMXDataGeneric.xsd | 12 + .../xml/xsd/schemas/SDMXDataGenericBase.xsd | 216 + .../xsd/schemas/SDMXDataGenericTimeSeries.xsd | 87 + .../xsd/schemas/SDMXDataStructureSpecific.xsd | 12 + .../schemas/SDMXDataStructureSpecificBase.xsd | 232 + .../SDMXDataStructureSpecificTimeSeries.xsd | 69 + .../resources/xml/xsd/schemas/SDMXMessage.xsd | 1182 ++++ .../xml/xsd/schemas/SDMXMessageFooter.xsd | 58 + .../xml/xsd/schemas/SDMXMetadataGeneric.xsd | 175 + .../schemas/SDMXMetadataStructureSpecific.xsd | 213 + .../resources/xml/xsd/schemas/SDMXQuery.xsd | 32 + .../xml/xsd/schemas/SDMXQueryBase.xsd | 650 +++ .../xsd/schemas/SDMXQueryCategorisation.xsd | 87 + .../xml/xsd/schemas/SDMXQueryCategory.xsd | 85 + .../xml/xsd/schemas/SDMXQueryCodelist.xsd | 84 + .../xml/xsd/schemas/SDMXQueryConcept.xsd | 100 + .../xml/xsd/schemas/SDMXQueryConstraint.xsd | 145 + .../xml/xsd/schemas/SDMXQueryData.xsd | 463 ++ .../xsd/schemas/SDMXQueryDataStructure.xsd | 265 + .../xml/xsd/schemas/SDMXQueryDataflow.xsd | 60 + .../schemas/SDMXQueryHierarchicalCodelist.xsd | 76 + .../xml/xsd/schemas/SDMXQueryMetadata.xsd | 274 + .../schemas/SDMXQueryMetadataStructure.xsd | 196 + .../xml/xsd/schemas/SDMXQueryMetadataflow.xsd | 60 + .../xml/xsd/schemas/SDMXQueryOrganisation.xsd | 104 + .../xml/xsd/schemas/SDMXQueryProcess.xsd | 135 + .../schemas/SDMXQueryProvisionAgreement.xsd | 81 + .../schemas/SDMXQueryReportingTaxonomy.xsd | 107 + .../xml/xsd/schemas/SDMXQuerySchema.xsd | 57 + .../xml/xsd/schemas/SDMXQueryStructureSet.xsd | 157 + .../xml/xsd/schemas/SDMXQueryStructures.xsd | 55 + .../xsd/schemas/SDMXQueryTransformation.xsd | 495 ++ .../xml/xsd/schemas/SDMXStructure.xsd | 685 +++ .../xml/xsd/schemas/SDMXStructureBase.xsd | 574 ++ .../schemas/SDMXStructureCategorisation.xsd | 34 + .../xml/xsd/schemas/SDMXStructureCategory.xsd | 65 + .../xml/xsd/schemas/SDMXStructureCodelist.xsd | 71 + .../xml/xsd/schemas/SDMXStructureConcept.xsd | 122 + .../xsd/schemas/SDMXStructureConstraint.xsd | 392 ++ .../schemas/SDMXStructureDataStructure.xsd | 565 ++ .../xml/xsd/schemas/SDMXStructureDataflow.xsd | 32 + .../SDMXStructureHierarchicalCodelist.xsd | 267 + .../SDMXStructureMetadataStructure.xsd | 500 ++ .../xsd/schemas/SDMXStructureMetadataflow.xsd | 32 + .../xsd/schemas/SDMXStructureOrganisation.xsd | 313 ++ .../xml/xsd/schemas/SDMXStructureProcess.xsd | 176 + .../SDMXStructureProvisionAgreement.xsd | 34 + .../SDMXStructureReportingTaxonomy.xsd | 83 + .../xsd/schemas/SDMXStructureStructureSet.xsd | 561 ++ .../schemas/SDMXStructureTransformation.xsd | 561 ++ .../test/resources/xml/xsd/schemas/xml.xsd | 80 + sdmx-ml30/build.gradle | 48 + .../xml30/data/StreamingXmlDataWriter.java | 848 +++ .../epam/jsdmx/xml30/data/XmlDataWriter.java | 8 + .../structure/reader/AgencySchemeReader.java | 103 + .../structure/reader/AnnotableReader.java | 98 + .../structure/reader/AttributeListReader.java | 196 + .../reader/CategorisationReader.java | 68 + .../reader/CategorySchemeMapReader.java | 85 + .../reader/CategorySchemeReader.java | 125 + .../structure/reader/CodeImplReader.java | 6 + .../xml30/structure/reader/CodeReader.java | 109 + .../reader/CodelistExtensionReader.java | 82 + .../structure/reader/CodelistReader.java | 107 + .../reader/ConceptSchemeMapReader.java | 86 + .../structure/reader/ConceptSchemeReader.java | 167 + .../reader/DataConstraintReader.java | 269 + .../reader/DataConsumerSchemeReader.java | 117 + .../reader/DataProviderSchemeReader.java | 110 + .../reader/DataStructureDefinitionReader.java | 113 + .../structure/reader/DataflowReader.java | 61 + .../structure/reader/DimensionListReader.java | 140 + .../reader/GeoFeatureSetCodeReader.java | 21 + .../reader/GeoGridCodelistReader.java | 105 + .../reader/GeographicCodelistReader.java | 107 + .../structure/reader/GridCodeReader.java | 18 + .../xml30/structure/reader/HeaderReader.java | 70 + .../reader/HierarchyAssociationReader.java | 77 + .../structure/reader/HierarchyReader.java | 199 + .../structure/reader/ItemSchemeMapReader.java | 48 + .../structure/reader/MappedComponent.java | 13 + .../structure/reader/MeasureListReader.java | 87 + .../reader/MemberSelectionReader.java | 162 + .../reader/MetadataConstraintReader.java | 154 + .../reader/MetadataProviderSchemeReader.java | 100 + .../MetadataProvisionAgreementReader.java | 69 + .../MetadataStructureDefinitionReader.java | 171 + .../structure/reader/MetadataflowReader.java | 87 + .../structure/reader/NameableReader.java | 19 + .../structure/reader/OrganisationReader.java | 199 + .../reader/OrganisationSchemeMapReader.java | 86 + .../reader/OrganisationUnitSchemeReader.java | 120 + .../xml30/structure/reader/ProcessReader.java | 262 + .../reader/ProvisionAgreementReader.java | 70 + .../reader/ReleaseCalendarReader.java | 44 + .../reader/ReportingTaxonomyMapReader.java | 87 + .../reader/ReportingTaxonomyReader.java | 150 + .../reader/RepresentationMapReader.java | 188 + .../reader/RepresentationReader.java | 140 + .../structure/reader/StructureMapReader.java | 423 ++ .../structure/reader/StructureMapUtils.java | 143 + .../structure/reader/ValueListReader.java | 113 + .../xml30/structure/reader/XmlReader.java | 75 + .../structure/reader/XmlReaderFactory.java | 311 ++ .../structure/reader/XmlReaderUtils.java | 225 + .../structure/reader/XmlStructureReader.java | 147 + .../structure/writer/AgencySchemeWriter.java | 68 + .../structure/writer/AnnotableWriter.java | 63 + .../structure/writer/AttributeListWriter.java | 169 + .../writer/CategorisationWriter.java | 62 + .../writer/CategorySchemeMapWriter.java | 50 + .../writer/CategorySchemeWriter.java | 65 + .../writer/CodeListExtensionWriter.java | 80 + .../xml30/structure/writer/CodeWriter.java | 62 + .../structure/writer/CodeWriterImpl.java | 9 + .../structure/writer/CodelistWriter.java | 69 + .../writer/CommonAttributesWriter.java | 68 + .../writer/ConceptSchemeMapWriter.java | 50 + .../structure/writer/ConceptSchemeWriter.java | 105 + .../xml30/structure/writer/ContactWriter.java | 59 + .../writer/DataConstraintWriter.java | 198 + .../writer/DataConsumerSchemeWriter.java | 69 + .../writer/DataProviderSchemeWriter.java | 70 + .../writer/DataStructureDefinitionWriter.java | 97 + .../structure/writer/DataflowWriter.java | 50 + .../structure/writer/DimensionListWriter.java | 99 + .../writer/GeoFeatureSetCodeWriter.java | 22 + .../writer/GeoGridCodelistWriter.java | 98 + .../writer/GeographicCodelistWriter.java | 96 + .../structure/writer/GridCodeWriter.java | 25 + .../writer/GroupDimensionListWriter.java | 45 + .../xml30/structure/writer/HeaderWriter.java | 81 + .../writer/HierarchyAssociationWriter.java | 66 + .../structure/writer/HierarchyWriter.java | 139 + .../structure/writer/ItemSchemeMapWriter.java | 65 + .../xml30/structure/writer/LinksWriter.java | 21 + .../structure/writer/MeasureListWriter.java | 58 + .../writer/MemberSelectionWriter.java | 143 + .../writer/MetadataConstraintWriter.java | 120 + .../writer/MetadataProviderSchemeWriter.java | 69 + .../MetadataProvisionAgreementWriter.java | 62 + .../MetadataStructureDefinitionWriter.java | 97 + .../structure/writer/MetadataflowWriter.java | 74 + .../structure/writer/NameableWriter.java | 20 + .../writer/OrganisationSchemeMapWriter.java | 71 + .../writer/OrganisationUnitSchemeWriter.java | 72 + .../structure/writer/OrganisationWriter.java | 67 + .../xml30/structure/writer/ProcessWriter.java | 185 + .../writer/ProvisionAgreementWriter.java | 58 + .../writer/ReleaseCalenderWriter.java | 36 + .../writer/ReportingTaxonomyMapWriter.java | 50 + .../writer/ReportingTaxonomyWriter.java | 93 + .../writer/RepresentationMapWriter.java | 152 + .../writer/RepresentationWriter.java | 209 + .../structure/writer/StructureMapWriter.java | 314 ++ .../xml30/structure/writer/UrnWriter.java | 44 + .../structure/writer/ValueListWriter.java | 65 + .../xml30/structure/writer/XmlConstants.java | 377 ++ .../structure/writer/XmlStructureWriter.java | 89 + .../xml30/structure/writer/XmlWriter.java | 66 + .../structure/writer/XmlWriterFactory.java | 131 + .../structure/writer/XmlWriterUtils.java | 161 + .../data/StreamingXmlDataWriterTest.java | 858 +++ .../com/epam/jsdmx/xml30/data/TestUtils.java | 328 ++ .../MaintainableArtifactsTestUtils.java | 1347 +++++ .../epam/jsdmx/xml30/structure/TestUtils.java | 68 + .../jsdmx/xml30/structure/XsdToXmlTest.java | 55 + .../reader/AgencySchemeReaderTest.java | 42 + .../structure/reader/BaseXmlReaderTest.java | 246 + .../reader/CategorisationReaderTest.java | 42 + .../reader/CategorySchemeMapReaderTest.java | 42 + .../reader/CategorySchemeReaderTest.java | 49 + .../structure/reader/CodelistReaderTest.java | 44 + .../reader/ConceptSchemeMapReaderTest.java | 42 + .../reader/ConceptSchemeReaderTest.java | 68 + .../reader/DataConstraintReaderTest.java | 116 + .../reader/DataConsumerSchemeReaderTest.java | 42 + .../reader/DataProviderSchemeReaderTest.java | 41 + .../DataStructureDefinitionReaderTest.java | 82 + .../structure/reader/DataflowReaderTest.java | 44 + .../reader/GeoGridCodelistReaderTest.java | 43 + .../reader/GeographicCodelistReaderTest.java | 43 + .../HierarchyAssociationReaderTest.java | 42 + .../structure/reader/HierarchyReaderTest.java | 43 + .../reader/MetadataConstraintReaderTest.java | 42 + .../MetadataProviderSchemeReaderTest.java | 41 + .../MetadataProvisionAgreementReaderTest.java | 42 + ...MetadataStructureDefinitionReaderTest.java | 44 + .../reader/MetadataflowReaderTest.java | 44 + .../OrganisationSchemeMapReaderTest.java | 42 + .../OrganisationUnitSchemeReaderTest.java | 43 + .../structure/reader/ProcessReaderTest.java | 42 + .../reader/ProvisionAgreementReaderTest.java | 42 + .../ReportingTaxonomyMapReaderTest.java | 42 + .../reader/ReportingTaxonomyReaderTest.java | 42 + .../reader/RepresentationMapReaderTest.java | 45 + .../reader/StructureMapReaderTest.java | 43 + .../structure/reader/ValueListReaderTest.java | 41 + .../reader/XmlStructureReaderTest.java | 99 + .../writer/AgencySchemeWriterTest.java | 52 + .../structure/writer/BaseXmlWriterTest.java | 359 ++ .../writer/CategorisationWriterTest.java | 52 + .../writer/CategorySchemeMapWriterTest.java | 52 + .../writer/CategorySchemeWriterTest.java | 50 + .../structure/writer/CodelistWriterTest.java | 52 + .../writer/ConceptSchemeMapWriterTest.java | 52 + .../writer/ConceptSchemeWriterTest.java | 53 + .../writer/DataConstraintWriterTest.java | 87 + .../writer/DataConsumerSchemeWriterTest.java | 53 + .../writer/DataProviderSchemeWriterTest.java | 53 + .../DataStructureDefinitionWriterTest.java | 58 + .../structure/writer/DataflowWriterTest.java | 52 + .../writer/GeoGridCodelistWriterTest.java | 53 + .../writer/GeographicCodelistWriterTest.java | 53 + .../HierarchyAssociationWriterTest.java | 53 + .../structure/writer/HierarchyWriterTest.java | 83 + .../writer/MetadataConstraintWriterTest.java | 52 + .../MetadataProviderSchemeWriterTest.java | 53 + .../MetadataProvisionAgreementWriterTest.java | 53 + ...MetadataStructureDefinitionWriterTest.java | 52 + .../writer/MetadataflowWriterTest.java | 51 + .../OrganisationSchemeMapWriterTest.java | 52 + .../OrganisationUnitSchemeWriterTest.java | 53 + .../structure/writer/ProcessWriterTest.java | 52 + .../writer/ProvisionAgreementWriterTest.java | 53 + .../ReportingTaxonomyMapWriterTest.java | 52 + .../writer/ReportingTaxonomyWriterTest.java | 53 + .../writer/RepresentationMapWriterTest.java | 52 + .../writer/StructureMapWriterTest.java | 52 + .../structure/writer/ValueListWriterTest.java | 52 + .../writer/XmlStructureWriterTest.java | 109 + .../xml30/structure/writer/XsdToXmlTest.java | 83 + .../src/test/resources/xml/agency-scheme.xml | 85 + sdmx-ml30/src/test/resources/xml/all.xml | 360 ++ .../src/test/resources/xml/categorisation.xml | 35 + .../resources/xml/category-scheme-map.xml | 49 + .../test/resources/xml/category-scheme.xml | 55 + sdmx-ml30/src/test/resources/xml/codelist.xml | 54 + .../test/resources/xml/concept-scheme-map.xml | 49 + .../src/test/resources/xml/concept-scheme.xml | 49 + .../xml/concept-scheme_with_enum_format.xml | 46 + .../resources/xml/data-constraints-empty.xml | 37 + .../xml/data-constraints-skip-validTo.xml | 46 + .../test/resources/xml/data-constraints.xml | 75 + .../resources/xml/data-consumer-scheme.xml | 57 + .../resources/xml/data-provider-scheme.xml | 61 + sdmx-ml30/src/test/resources/xml/dataflow.xml | 34 + .../dataquery/xml_3.0_data_query_atts_obs.xml | 27 + .../xml_3.0_data_query_atts_series.xml | 29 + .../xml_3.0_data_query_dataset_atts.xml | 35 + .../dataquery/xml_3.0_data_query_groups.xml | 28 + .../xml_3.0_data_query_groups_meta.xml | 35 + .../xml_3.0_data_query_groups_obs.xml | 30 + .../xml_3.0_data_query_groups_series.xml | 32 + .../xml/dataquery/xml_3.0_data_query_meta.xml | 52 + .../dataquery/xml_3.0_data_query_meta2.xml | 52 + .../xml_3.0_data_query_meta_flat.xml | 41 + .../xml_3.0_data_query_meta_multi.xml | 42 + .../xml_3.0_data_query_multiling_atts.xml | 58 + .../xml_3.0_data_query_multiling_atts_obs.xml | 40 + .../xml/dataquery/xml_3.0_data_query_obs.xml | 22 + .../dataquery/xml_3.0_data_query_series.xml | 31 + .../xml_3.0_data_query_series_and_obs.xml | 38 + .../xml_3.0_data_query_series_multi.xml | 37 + .../xml/dataquery/xml_3.0_dataset.xml | 36 + .../xml/dataquery/xml_3.0_dataset_flat.xml | 37 + sdmx-ml30/src/test/resources/xml/dsd.xml | 111 + .../xml/dsd_with_df_attr_relationship.xml | 97 + .../resources/xml/dsd_with_enumFormat.xml | 113 + .../resources/xml/geographical-codelist.xml | 55 + .../test/resources/xml/geogrid-codelist.xml | 57 + .../resources/xml/hierarchy-association.xml | 36 + .../src/test/resources/xml/hierarchy.xml | 49 + .../test/resources/xml/hierarchy_names.xml | 50 + sdmx-ml30/src/test/resources/xml/mdsd.xml | 52 + .../resources/xml/metadata-constraints.xml | 52 + .../xml/metadata-provider-scheme.xml | 61 + .../xml/metadata-provision-agreement.xml | 35 + .../src/test/resources/xml/metadata-set.xml | 41 + .../src/test/resources/xml/metadataflow.xml | 36 + .../resources/xml/organisation-scheme-map.xml | 49 + .../xml/organisation-unit-scheme.xml | 64 + sdmx-ml30/src/test/resources/xml/process.xml | 69 + .../resources/xml/provision-agreement.xml | 35 + .../resources/xml/reporting-taxonomy-map.xml | 49 + .../test/resources/xml/reporting-taxonomy.xml | 51 + .../test/resources/xml/representation_map.xml | 41 + .../src/test/resources/xml/structure_map.xml | 69 + .../src/test/resources/xml/valuelist.xml | 49 + .../resources/xml/xsd/schemas/SDMXCommon.xsd | 1349 +++++ .../xml/xsd/schemas/SDMXCommonReferences.xsd | 1631 ++++++ .../xsd/schemas/SDMXDataStructureSpecific.xsd | 260 + .../resources/xml/xsd/schemas/SDMXMessage.xsd | 514 ++ .../xml/xsd/schemas/SDMXMessageFooter.xsd | 57 + .../xml/xsd/schemas/SDMXMetadataGeneric.xsd | 112 + .../xml/xsd/schemas/SDMXRegistry.xsd | 14 + .../xml/xsd/schemas/SDMXRegistryBase.xsd | 224 + .../xsd/schemas/SDMXRegistryRegistration.xsd | 218 + .../xml/xsd/schemas/SDMXRegistryStructure.xsd | 98 + .../xsd/schemas/SDMXRegistrySubscription.xsd | 603 ++ .../xml/xsd/schemas/SDMXStructure.xsd | 1009 ++++ .../xml/xsd/schemas/SDMXStructureBase.xsd | 486 ++ .../xml/xsd/schemas/SDMXStructureCL.xsd | 646 +++ .../schemas/SDMXStructureCategorisation.xsd | 51 + .../xml/xsd/schemas/SDMXStructureCategory.xsd | 69 + .../xml/xsd/schemas/SDMXStructureCodelist.xsd | 365 ++ .../xml/xsd/schemas/SDMXStructureConcept.xsd | 126 + .../xsd/schemas/SDMXStructureConstraint.xsd | 765 +++ .../schemas/SDMXStructureDataStructure.xsd | 638 +++ .../xml/xsd/schemas/SDMXStructureDataflow.xsd | 34 + .../SDMXStructureHierarchicalCodelist.xsd | 237 + .../SDMXStructureMetadataStructure.xsd | 166 + .../xsd/schemas/SDMXStructureMetadataflow.xsd | 51 + .../xsd/schemas/SDMXStructureOrganisation.xsd | 371 ++ .../xml/xsd/schemas/SDMXStructureProcess.xsd | 210 + .../SDMXStructureProvisionAgreement.xsd | 95 + .../SDMXStructureReportingTaxonomy.xsd | 86 + .../SDMXStructureStructureMappings.xsd | 478 ++ .../schemas/SDMXStructureTransformation.xsd | 670 +++ .../resources/xml/xsd/schemas/codelist.xsd | 365 ++ .../test/resources/xml/xsd/schemas/xml.xsd | 80 + sdmx30-serializer/build.gradle | 46 + .../serializer/common/ReferenceAdapter.java | 18 + ...taStructureLocalRepresentationAdapter.java | 9 + ...meDimensionLocalRepresentationAdapter.java | 7 + .../DataStructure30To21ComponentAdapter.java | 7 + ...taStructure30To21ComponentAdapterImpl.java | 136 + .../serializer/sdmx21/MetadataConverter.java | 10 + .../serializer/sdmx21/ReferenceResolver.java | 11 + .../serializer/sdmx30/common/ActionType.java | 46 + .../sdmx30/common/DataLocation.java | 9 + .../serializer/sdmx30/common/DataWriter.java | 36 + .../sdmx30/common/DatasetHeader.java | 69 + .../sdmx30/common/DatasetHeaderImpl.java | 24 + .../common/DatasetStructureReference.java | 27 + .../common/DatasetStructureReferenceImpl.java | 14 + .../sdmx30/common/DefaultHeaderProvider.java | 54 + .../common/DefaultReferenceAdapter.java | 16 + .../serializer/sdmx30/common/Header.java | 35 + .../sdmx30/common/InMemoryDataLocation.java | 22 + .../sdmx30/common/MetadataAttributeValue.java | 28 + .../MultilingualMetadataAttributeValue.java | 48 + .../sdmx30/common/ProvisionAgreement.java | 12 + .../common/SimpleMetadataAttributeValue.java | 51 + .../sdmx30/structure/StructureReader.java | 11 + .../sdmx30/structure/StructureWriter.java | 9 + .../util/DateTimeConverterUtil.java | 13 + .../jsdmx/serializer/util/DimensionUtil.java | 17 + settings.gradle | 5 + 792 files changed, 92760 insertions(+), 9 deletions(-) create mode 100644 sdmx-json10/build.gradle create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/AgencySchemeWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/AnnotableWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/AttributeListWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/BaseWriterJson.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CategorisationWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CategorySchemeWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CodeWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CodeWriterImpl.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CodelistWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ComponentWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ConceptRoleWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ConceptSchemeWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ContactsWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ContentConstraintWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CubeRegionWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataKeySetsWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataStructureComponentsUtils.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataStructureDefinitionWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataflowWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DefaultHeaderProvider.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DimensionListWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/GroupDimensionListWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/HierarchicalCodelistWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/IdentifiableWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/Json10StructureWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/Json10WriterFactory.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/JsonRuntimeException.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/LinksWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MaintainableWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MeasureListWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MetaWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MetadataConstraintWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/NameableWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/OrganisationWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/RepresentationWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/SelectionValueWriter.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/StructureUtils.java create mode 100644 sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/VersionableWriter.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/MaintainableArtifactsTestUtils.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/SdmxSourceCompatibilityTester.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/TestUtils.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/AttributeListWriterJsonTest.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/CategorisationWriterTest.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/CategorySchemeWriterTest.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/CodelistWriterTest.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/ConceptSchemeWriterTest.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/ContentConstraintWriterTest.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/DataStructureDefinitionWriterTest.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/DataflowWriterTest.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/DimensionListWriterJsonTest.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/GenericTest.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/GroupDimensionListWriterJsonTest.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/HierarchicalCodelistWriterTest.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/Json10StructureWriterTest.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/JsonWriterTestBase.java create mode 100644 sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/MeasureListWriterJsonTest.java create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/category-schema2.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/codelist_wild.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/concept-schema.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/data-flow.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-attr.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-attr_and_null.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-attr_null.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-components_empty.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-components_null.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-dim.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-dim_and_null.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-dim_null.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-full.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-meas.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-meas_and_null.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-meas_null.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/hierarchy.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/json.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/metadata-all-artefacts.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/structure-maps-full.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/structure-maps-list-full.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/structures-all-artefacts.json create mode 100644 sdmx-json10/src/test/resources/deserialization.expected/test.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/agency-scheme.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/attribute-list.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/attribute-list_empty.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/categorisation.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/category-schema.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/category-scheme-map.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/codelist.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/concept-scheme-map.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/concept-scheme.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/data-constraint.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/data-consumer-scheme.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/data-flow.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/data-provider-scheme.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/data-structure-definition-order.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/data-structure-definition.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/dimension-list.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/dimension-list_empty.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/empty-structure.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/expected-flat-json-streamer-response.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/geocodelist.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/geogridcodelist.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/group-dimension-list.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/hierarchy.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/hierarchy_flat.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/measure-list.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/measure-list_empty.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/meta-data-constraint.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/metadata-constraint.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/metadata-flow.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/metadata-provider-scheme.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/metadata-provision-agreement.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/metadata-structure-definition.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/metadata.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/metadataset.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/organisation-scheme-map.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/organisation-unit-scheme.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/process.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/provision-agreement.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/reporting-taxonomy-map.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/reporting-taxonomy.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/representation-map.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/structure-map-with-null-map.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/structure-map-with-null-target-source.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/structure-map.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/structure.json create mode 100644 sdmx-json10/src/test/resources/serialization.expected/valuelist.json create mode 100644 sdmx-json20/build.gradle create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/AgencySchemeReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/AnnotableReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/AttributeListReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CategorisationReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CategorySchemeMapReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CategorySchemeReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodeImplReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodeReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodelistExtensionReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodelistReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ConceptRoleUtils.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ConceptSchemeMapReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ConceptSchemeReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ContactReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CubeRegionReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataConstraintReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataConsumerSchemeReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataFlowReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataKeySetReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataProviderSchemeReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataStructureDefinitionReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DimensionListReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GeoFeatureSetCodeReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GeoGridCodelistReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GeographicCodelistReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GridCodeReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/HierarchyAssociationReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/HierarchyReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/IdentifiableReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ItemMapReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/JsonReaderFactory.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/JsonRuntimeException.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/JsonStructureReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MaintainableReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MeasureListReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MemberSelectionReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetaDataStructureDefinitionReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetaReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataConstraintReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataFlowReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataProviderSchemeReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataProvisionAgreementReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/NameableReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/OrganisationReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/OrganisationSchemeMapReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/OrganisationUnitSchemeReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ProcessReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ProvisionAgreementReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReaderUtils.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReleaseCalendarReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReportingTaxonomyMapReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReportingTaxonomyReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/RepresentationMapReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/RepresentationReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/StructureMapReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ValueListReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/VersionableReader.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/AgencySchemeWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/AnnotableWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/AttributeListWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/BaseWriterJson.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CategorisationWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CategorySchemeMapWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CategorySchemeWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodeWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodeWriterImpl.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodelistExtensionWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodelistWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ComponentWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ConceptRoleWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ConceptSchemeMapWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ConceptSchemeWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ContactsWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CubeRegionWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataConstraintWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataConsumerSchemeWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataKeySetsWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataProviderSchemeWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataStructureComponentsUtils.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataStructureDefinitionWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataflowWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DateTimeWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DimensionListWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GeoFeatureSetCodeWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GeoGridCodelistWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GeographicCodelistWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GridCodeWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GroupDimensionListWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/HierarchyAssociationWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/HierarchyWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/IdentifiableWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ItemMapWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/JsonStructureWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/JsonWriterFactory.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/LinksWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MaintainableWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MappedComponent.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MeasureListWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MemberSelectionWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetaWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataConstraintWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataProviderSchemeWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataProvisionAgreementWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataStructureDefinitionWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataflowWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/NameableWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/OrganisationSchemeMapWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/OrganisationUnitSchemeWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/OrganisationWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ProcessWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ProvisionAgreementWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ReportingTaxonomyMapWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ReportingTaxonomyWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/RepresentationMapWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/RepresentationWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/StructureMapUtils.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/StructureMapWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/StructureUtils.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ValueListWriter.java create mode 100644 sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/VersionableWriter.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/MaintainableArtifactsTestUtils.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/TestUtils.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/ArtefactAssertion.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/BaseJsonReaderTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/CategorisationReaderTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/CategorySchemeReaderTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/CodelistReaderTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/ConceptSchemeReaderTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/DataConstraintReaderTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/DataReaderTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/DataStructureDefinitionReaderTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/HierarchyReaderTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/MetadataFlowReaderTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/MetadataStructureDefinitionReaderTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/RepresentationMapReaderTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/StructureMapReaderTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/AttributeListWriterJsonTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/BaseJsonWriterTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/CategorisationWriterTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/CategorySchemeWriterTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/CodelistWriterTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/ConceptSchemeWriterTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/DataConstraintWriterTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/DataStructureDefinitionWriterTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/DimensionListWriterJsonTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/GroupDimensionListWriterJsonTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/HierarchyWriterTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/JsonStructureWriterTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/MeasureListWriterJsonTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/MetaDataStructureDefinitionWriterTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/MetadataflowWriterTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/RepresentationMapWriterTest.java create mode 100644 sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/StructureMapWriterTest.java create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/category-schema2.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/codelist_wild.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/concept-schema.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/data-flow.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-attr.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-attr_and_null.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-attr_null.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-components_empty.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-components_null.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-dim.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-dim_and_null.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-dim_null.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-full.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-meas.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-meas_and_null.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-meas_null.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/hierarchy.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/hierarchy2.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/json.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/metadata-all-artefacts.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/structure-maps-full.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/structure-maps-list-full.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/structures-all-artefacts.json create mode 100644 sdmx-json20/src/test/resources/deserialization.expected/test.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/agency-scheme.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/attribute-list.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/attribute-list_empty.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/categorisation.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/category-schema.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/category-scheme-map.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/codelist.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/concept-scheme-enumerated-concept.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/concept-scheme-map.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/concept-scheme.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/data-constraint-empty.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/data-constraint.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/data-consumer-scheme.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/data-flow.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/data-provider-scheme.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/data-structure-definition-order.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/data-structure-definition.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/dimension-list.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/dimension-list_empty.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/empty-structure.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/expected-flat-json-streamer-response.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/geocodelist.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/geogridcodelist.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/group-dimension-list.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/hierarchy-association.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/hierarchy.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/measure-list.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/measure-list_empty.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/metadata-constraint.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/metadata-flow.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/metadata-provider-scheme.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/metadata-provision-agreement.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/metadata-structure-definition-multi-attributes.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/metadata-structure-definition.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/metadata.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/metadataset.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/organisation-scheme-map.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/organisation-unit-scheme.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/process.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/provision-agreement.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/reporting-taxonomy-map.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/reporting-taxonomy.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/representation-map.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/structure-map-with-null-map.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/structure-map-with-null-target-source.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/structure-map.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/structure.json create mode 100644 sdmx-json20/src/test/resources/serialization.expected/valuelist.json create mode 100644 sdmx-ml21/build.gradle create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/AnnotableWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/AttributeListWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CategorisationWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CategorySchemeWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CodeWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CodeWriterImpl.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CodelistWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CommonAttributesWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ConceptSchemeWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ContactWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ContentConstraintWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CubeRegionWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DataKeySetsWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DataStructureDefinitionWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DataflowWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DimensionListWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/GroupDimensionListWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/HeaderWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/HierarchicalCodelistWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ItemSchemeMapWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/MeasureListWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/MemberSelectionWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/MetadataConstraintWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/NameableWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/OrganisationSchemeWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/OrganisationWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ReferenceWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ReleaseCalenderWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/RepresentationWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/Xml21StructureWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/Xml21WriterFactory.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/XmlConstants.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/XmlWriter.java create mode 100644 sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/XmlWriterUtils.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/MaintainableArtifactsTestUtils.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/SdmxSourceCompatibilityTester.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/TestUtils.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/BaseXmlWriterTest.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/CategorisationWriterTest.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/CategorySchemeWriterTest.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/CodelistWriterTest.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/ConceptSchemeWriterTest.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/ContentConstraintWriterTest.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataConsumerSchemeWriterTest.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataProviderSchemeWriterTest.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataStructureDefinitionWriterTest.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataflowWriterTest.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/HierarchicalCodelistWriterTest.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/OrganisationSchemeWriterTest.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/Xml21StructureWriterTest.java create mode 100644 sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/XsdToXmlTest.java create mode 100644 sdmx-ml21/src/test/resources/xml/agency-scheme.xml create mode 100644 sdmx-ml21/src/test/resources/xml/all.xml create mode 100644 sdmx-ml21/src/test/resources/xml/categorisation.xml create mode 100644 sdmx-ml21/src/test/resources/xml/categorisation_with_hierarchy_ref.xml create mode 100644 sdmx-ml21/src/test/resources/xml/category-scheme-map.xml create mode 100644 sdmx-ml21/src/test/resources/xml/category-scheme.xml create mode 100644 sdmx-ml21/src/test/resources/xml/codelist.xml create mode 100644 sdmx-ml21/src/test/resources/xml/concept-scheme-map.xml create mode 100644 sdmx-ml21/src/test/resources/xml/concept-scheme.xml create mode 100644 sdmx-ml21/src/test/resources/xml/data-constraints.xml create mode 100644 sdmx-ml21/src/test/resources/xml/data-consumer-scheme.xml create mode 100644 sdmx-ml21/src/test/resources/xml/data-provider-scheme.xml create mode 100644 sdmx-ml21/src/test/resources/xml/dataflow.xml create mode 100644 sdmx-ml21/src/test/resources/xml/dsd.xml create mode 100644 sdmx-ml21/src/test/resources/xml/geographical-codelist.xml create mode 100644 sdmx-ml21/src/test/resources/xml/geogrid-codelist.xml create mode 100644 sdmx-ml21/src/test/resources/xml/hierarchy.xml create mode 100644 sdmx-ml21/src/test/resources/xml/hierarchy_names.xml create mode 100644 sdmx-ml21/src/test/resources/xml/metadata-constraints.xml create mode 100644 sdmx-ml21/src/test/resources/xml/metadata-provider-scheme.xml create mode 100644 sdmx-ml21/src/test/resources/xml/metadata-provision-agreement.xml create mode 100644 sdmx-ml21/src/test/resources/xml/organisation-scheme-map.xml create mode 100644 sdmx-ml21/src/test/resources/xml/organisation-unit-scheme.xml create mode 100644 sdmx-ml21/src/test/resources/xml/process.xml create mode 100644 sdmx-ml21/src/test/resources/xml/provision-agreement.xml create mode 100644 sdmx-ml21/src/test/resources/xml/reporting-taxonomy-map.xml create mode 100644 sdmx-ml21/src/test/resources/xml/reporting-taxonomy.xml create mode 100644 sdmx-ml21/src/test/resources/xml/representation_map.xml create mode 100644 sdmx-ml21/src/test/resources/xml/structure_map.xml create mode 100644 sdmx-ml21/src/test/resources/xml/valuelist.xml create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXCommon.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXCommonReferences.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataGeneric.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataGenericBase.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataGenericTimeSeries.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecific.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecificBase.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecificTimeSeries.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMessage.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMessageFooter.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMetadataGeneric.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMetadataStructureSpecific.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQuery.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryBase.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryCategorisation.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryCategory.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryCodelist.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryConcept.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryConstraint.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryData.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryDataStructure.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryDataflow.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryHierarchicalCodelist.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryMetadata.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryMetadataStructure.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryMetadataflow.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryOrganisation.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryProcess.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryProvisionAgreement.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryReportingTaxonomy.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQuerySchema.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryStructureSet.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryStructures.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryTransformation.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructure.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureBase.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureCategorisation.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureCategory.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureCodelist.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureConcept.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureConstraint.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureDataStructure.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureDataflow.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureHierarchicalCodelist.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataStructure.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataflow.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureOrganisation.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureProcess.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureProvisionAgreement.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureReportingTaxonomy.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureStructureSet.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureTransformation.xsd create mode 100644 sdmx-ml21/src/test/resources/xml/xsd/schemas/xml.xsd create mode 100644 sdmx-ml30/build.gradle create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/data/StreamingXmlDataWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/data/XmlDataWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/AgencySchemeReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/AnnotableReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/AttributeListReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CategorisationReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeMapReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodeImplReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodeReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodelistExtensionReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodelistReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeMapReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataConstraintReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataConsumerSchemeReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataProviderSchemeReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataStructureDefinitionReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataflowReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DimensionListReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GeoFeatureSetCodeReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GeoGridCodelistReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GeographicCodelistReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GridCodeReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/HeaderReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/HierarchyAssociationReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/HierarchyReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ItemSchemeMapReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MappedComponent.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MeasureListReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MemberSelectionReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataConstraintReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataProviderSchemeReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataProvisionAgreementReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataStructureDefinitionReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataflowReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/NameableReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/OrganisationReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/OrganisationSchemeMapReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/OrganisationUnitSchemeReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ProcessReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ProvisionAgreementReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ReleaseCalendarReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyMapReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/RepresentationMapReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/RepresentationReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/StructureMapReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/StructureMapUtils.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ValueListReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlReaderFactory.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlReaderUtils.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlStructureReader.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/AgencySchemeWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/AnnotableWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/AttributeListWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CategorisationWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeMapWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodeListExtensionWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodeWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodeWriterImpl.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodelistWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CommonAttributesWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeMapWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ContactWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataConstraintWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataConsumerSchemeWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataProviderSchemeWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataStructureDefinitionWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataflowWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DimensionListWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GeoFeatureSetCodeWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GeoGridCodelistWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GeographicCodelistWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GridCodeWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GroupDimensionListWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/HeaderWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/HierarchyAssociationWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/HierarchyWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ItemSchemeMapWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/LinksWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MeasureListWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MemberSelectionWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataConstraintWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataProviderSchemeWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataProvisionAgreementWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataStructureDefinitionWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataflowWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/NameableWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/OrganisationSchemeMapWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/OrganisationUnitSchemeWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/OrganisationWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ProcessWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ProvisionAgreementWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ReleaseCalenderWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyMapWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/RepresentationMapWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/RepresentationWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/StructureMapWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/UrnWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ValueListWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlConstants.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlStructureWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlWriter.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlWriterFactory.java create mode 100644 sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlWriterUtils.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/data/StreamingXmlDataWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/data/TestUtils.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/MaintainableArtifactsTestUtils.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/TestUtils.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/XsdToXmlTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/AgencySchemeReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/BaseXmlReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CategorisationReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeMapReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CodelistReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeMapReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataConstraintReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataConsumerSchemeReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataProviderSchemeReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataStructureDefinitionReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataflowReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/GeoGridCodelistReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/GeographicCodelistReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/HierarchyAssociationReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/HierarchyReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataConstraintReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataProviderSchemeReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataProvisionAgreementReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataStructureDefinitionReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataflowReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/OrganisationSchemeMapReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/OrganisationUnitSchemeReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ProcessReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ProvisionAgreementReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyMapReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/RepresentationMapReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/StructureMapReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ValueListReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/XmlStructureReaderTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/AgencySchemeWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/BaseXmlWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CategorisationWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeMapWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CodelistWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeMapWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataConstraintWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataConsumerSchemeWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataProviderSchemeWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataStructureDefinitionWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataflowWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/GeoGridCodelistWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/GeographicCodelistWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/HierarchyAssociationWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/HierarchyWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataConstraintWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataProviderSchemeWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataProvisionAgreementWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataStructureDefinitionWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataflowWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/OrganisationSchemeMapWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/OrganisationUnitSchemeWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ProcessWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ProvisionAgreementWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyMapWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/RepresentationMapWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/StructureMapWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ValueListWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/XmlStructureWriterTest.java create mode 100644 sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/XsdToXmlTest.java create mode 100644 sdmx-ml30/src/test/resources/xml/agency-scheme.xml create mode 100644 sdmx-ml30/src/test/resources/xml/all.xml create mode 100644 sdmx-ml30/src/test/resources/xml/categorisation.xml create mode 100644 sdmx-ml30/src/test/resources/xml/category-scheme-map.xml create mode 100644 sdmx-ml30/src/test/resources/xml/category-scheme.xml create mode 100644 sdmx-ml30/src/test/resources/xml/codelist.xml create mode 100644 sdmx-ml30/src/test/resources/xml/concept-scheme-map.xml create mode 100644 sdmx-ml30/src/test/resources/xml/concept-scheme.xml create mode 100644 sdmx-ml30/src/test/resources/xml/concept-scheme_with_enum_format.xml create mode 100644 sdmx-ml30/src/test/resources/xml/data-constraints-empty.xml create mode 100644 sdmx-ml30/src/test/resources/xml/data-constraints-skip-validTo.xml create mode 100644 sdmx-ml30/src/test/resources/xml/data-constraints.xml create mode 100644 sdmx-ml30/src/test/resources/xml/data-consumer-scheme.xml create mode 100644 sdmx-ml30/src/test/resources/xml/data-provider-scheme.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataflow.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_atts_obs.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_atts_series.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_dataset_atts.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups_meta.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups_obs.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups_series.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta2.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta_flat.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta_multi.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_multiling_atts.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_multiling_atts_obs.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_obs.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_series.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_series_and_obs.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_series_multi.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_dataset.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_dataset_flat.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dsd.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dsd_with_df_attr_relationship.xml create mode 100644 sdmx-ml30/src/test/resources/xml/dsd_with_enumFormat.xml create mode 100644 sdmx-ml30/src/test/resources/xml/geographical-codelist.xml create mode 100644 sdmx-ml30/src/test/resources/xml/geogrid-codelist.xml create mode 100644 sdmx-ml30/src/test/resources/xml/hierarchy-association.xml create mode 100644 sdmx-ml30/src/test/resources/xml/hierarchy.xml create mode 100644 sdmx-ml30/src/test/resources/xml/hierarchy_names.xml create mode 100644 sdmx-ml30/src/test/resources/xml/mdsd.xml create mode 100644 sdmx-ml30/src/test/resources/xml/metadata-constraints.xml create mode 100644 sdmx-ml30/src/test/resources/xml/metadata-provider-scheme.xml create mode 100644 sdmx-ml30/src/test/resources/xml/metadata-provision-agreement.xml create mode 100644 sdmx-ml30/src/test/resources/xml/metadata-set.xml create mode 100644 sdmx-ml30/src/test/resources/xml/metadataflow.xml create mode 100644 sdmx-ml30/src/test/resources/xml/organisation-scheme-map.xml create mode 100644 sdmx-ml30/src/test/resources/xml/organisation-unit-scheme.xml create mode 100644 sdmx-ml30/src/test/resources/xml/process.xml create mode 100644 sdmx-ml30/src/test/resources/xml/provision-agreement.xml create mode 100644 sdmx-ml30/src/test/resources/xml/reporting-taxonomy-map.xml create mode 100644 sdmx-ml30/src/test/resources/xml/reporting-taxonomy.xml create mode 100644 sdmx-ml30/src/test/resources/xml/representation_map.xml create mode 100644 sdmx-ml30/src/test/resources/xml/structure_map.xml create mode 100644 sdmx-ml30/src/test/resources/xml/valuelist.xml create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXCommon.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXCommonReferences.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecific.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXMessage.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXMessageFooter.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXMetadataGeneric.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistry.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistryBase.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistryRegistration.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistryStructure.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistrySubscription.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructure.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureBase.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCL.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCategorisation.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCategory.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCodelist.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureConcept.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureConstraint.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureDataStructure.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureDataflow.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureHierarchicalCodelist.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataStructure.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataflow.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureOrganisation.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureProcess.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureProvisionAgreement.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureReportingTaxonomy.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureStructureMappings.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureTransformation.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/codelist.xsd create mode 100644 sdmx-ml30/src/test/resources/xml/xsd/schemas/xml.xsd create mode 100644 sdmx30-serializer/build.gradle create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/common/ReferenceAdapter.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/common/StubDataStructureLocalRepresentationAdapter.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/common/TimeDimensionLocalRepresentationAdapter.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/DataStructure30To21ComponentAdapter.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/DataStructure30To21ComponentAdapterImpl.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/MetadataConverter.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/ReferenceResolver.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/ActionType.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DataLocation.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DataWriter.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetHeader.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetHeaderImpl.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetStructureReference.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetStructureReferenceImpl.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DefaultHeaderProvider.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DefaultReferenceAdapter.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/Header.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/InMemoryDataLocation.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/MetadataAttributeValue.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/MultilingualMetadataAttributeValue.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/ProvisionAgreement.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/SimpleMetadataAttributeValue.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/structure/StructureReader.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/structure/StructureWriter.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/util/DateTimeConverterUtil.java create mode 100644 sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/util/DimensionUtil.java diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 678a13c..7d17d00 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - java: [ '11' ] + java: [ '17' ] os: [ 'ubuntu-latest', 'windows-latest', 'macos-latest' ] steps: - name: Checkout code diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 838acbe..9eaa8d8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -46,7 +46,7 @@ jobs: strategy: fail-fast: false matrix: - java: [ '11' ] + java: [ '17' ] os: [ 'ubuntu-latest', 'windows-latest', 'macos-latest' ] steps: - name: Checkout code @@ -110,7 +110,7 @@ jobs: - name: Setup java uses: actions/setup-java@v2 with: - java-version: 11 + java-version: 17 distribution: 'temurin' - name: Publish jars run: ./gradlew publish diff --git a/build.gradle b/build.gradle index 8a736c8..237e9de 100644 --- a/build.gradle +++ b/build.gradle @@ -9,8 +9,8 @@ subprojects { showViolations = true } - sourceCompatibility = 11 - targetCompatibility = 11 + sourceCompatibility = 17 + targetCompatibility = 17 ext.isReleaseVersion = !version.endsWith("SNAPSHOT") diff --git a/gradle.properties b/gradle.properties index 2ff6da7..187f619 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,8 +2,25 @@ group=com.epam.jsdmx version=1.0.0-SNAPSHOT #dependencies +jupiter_version=5.8.2 lombok_version=1.18.24 org_apache_commons_commons_collections4_version=4.4 -org_apache_commons_commons_lang3_version=3.12.0 -jupiter_version=5.8.2 -assertj_version=3.22.0 \ No newline at end of file +org_apache_commons_commons_lang3_version=3.18.0 +jupiter_api_version=5.11.4 +jupiter_engine_version=5.11.4 +mockito_version=5.4.0 +json_unit_version=4.1.1 +spring_version=6.2.10 +log4j_version=2.24.3 +sdmx_version=2.0.6 +mapstruct_version=1.5.3.Final +fasterxml_version=2.18.4 +fasterxml_databind_version=2.18.4 +guava_version=33.0.0-jre +openc_csv_version=5.12.0 +random_beans_version=3.9.0 +jsonschema2pojo_version=1.2.2 +junit_version=4.13.2 +assertj_version=3.26.3 +xmlunit_legacy_version=2.10.3 +xml_bind_jaxb_version=3.0.2 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927a4d4fb3f96a785543079b8df6723c946b..1b33c55baabb587c669f562ae36f953de2481846 100644 GIT binary patch literal 43764 zcma&OWmKeVvL#I6?i3D%6z=Zs?ofE*?rw#G$eqJB ziT4y8-Y@s9rkH0Tz>ll(^xkcTl)CY?rS&9VNd66Yc)g^6)JcWaY(5$5gt z8gr3SBXUTN;~cBgz&})qX%#!Fxom2Yau_`&8)+6aSN7YY+pS410rRUU*>J}qL0TnJ zRxt*7QeUqTh8j)Q&iavh<}L+$Jqz))<`IfKussVk%%Ah-Ti?Eo0hQH!rK%K=#EAw0 zwq@@~XNUXRnv8$;zv<6rCRJ6fPD^hfrh;0K?n z=p!u^3xOgWZ%f3+?+>H)9+w^$Tn1e;?UpVMJb!!;f)`6f&4|8mr+g)^@x>_rvnL0< zvD0Hu_N>$(Li7|Jgu0mRh&MV+<}`~Wi*+avM01E)Jtg=)-vViQKax!GeDc!xv$^mL z{#OVBA$U{(Zr8~Xm|cP@odkHC*1R8z6hcLY#N@3E-A8XEvpt066+3t9L_6Zg6j@9Q zj$$%~yO-OS6PUVrM2s)(T4#6=JpI_@Uz+!6=GdyVU?`!F=d;8#ZB@(5g7$A0(`eqY z8_i@3w$0*es5mrSjhW*qzrl!_LQWs4?VfLmo1Sd@Ztt53+etwzAT^8ow_*7Jp`Y|l z*UgSEwvxq+FYO!O*aLf-PinZYne7Ib6ny3u>MjQz=((r3NTEeU4=-i0LBq3H-VJH< z^>1RE3_JwrclUn9vb7HcGUaFRA0QHcnE;6)hnkp%lY1UII#WPAv?-;c?YH}LWB8Nl z{sx-@Z;QxWh9fX8SxLZk8;kMFlGD3Jc^QZVL4nO)1I$zQwvwM&_!kW+LMf&lApv#< zur|EyC|U@5OQuph$TC_ZU`{!vJp`13e9alaR0Dbn5ikLFH7>eIz4QbV|C=%7)F=qo z_>M&5N)d)7G(A%c>}UCrW!Ql_6_A{?R7&CL`;!KOb3 z8Z=$YkV-IF;c7zs{3-WDEFJzuakFbd*4LWd<_kBE8~BFcv}js_2OowRNzWCtCQ6&k z{&~Me92$m*@e0ANcWKuz)?YjB*VoSTx??-3Cc0l2U!X^;Bv@m87eKHukAljrD54R+ zE;@_w4NPe1>3`i5Qy*3^E9x#VB6?}v=~qIprrrd5|DFkg;v5ixo0IsBmik8=Y;zv2 z%Bcf%NE$a44bk^`i4VwDLTbX=q@j9;JWT9JncQ!+Y%2&HHk@1~*L8-{ZpY?(-a9J-1~<1ltr9i~D9`P{XTIFWA6IG8c4;6bFw*lzU-{+?b&%OcIoCiw00n>A1ra zFPE$y@>ebbZlf(sN_iWBzQKDV zmmaLX#zK!@ZdvCANfwV}9@2O&w)!5gSgQzHdk2Q`jG6KD7S+1R5&F)j6QTD^=hq&7 zHUW+r^da^%V(h(wonR(j?BOiC!;y=%nJvz?*aW&5E87qq;2z`EI(f zBJNNSMFF9U{sR-af5{IY&AtoGcoG)Iq-S^v{7+t0>7N(KRoPj;+2N5;9o_nxIGjJ@ z7bYQK)bX)vEhy~VL%N6g^NE@D5VtV+Q8U2%{ji_=6+i^G%xeskEhH>Sqr194PJ$fB zu1y^){?9Vkg(FY2h)3ZHrw0Z<@;(gd_dtF#6y_;Iwi{yX$?asr?0N0_B*CifEi7<6 zq`?OdQjCYbhVcg+7MSgIM|pJRu~`g?g3x?Tl+V}#$It`iD1j+!x+!;wS0+2e>#g?Z z*EA^k7W{jO1r^K~cD#5pamp+o@8&yw6;%b|uiT?{Wa=4+9<}aXWUuL#ZwN1a;lQod zW{pxWCYGXdEq9qAmvAB904}?97=re$>!I%wxPV#|f#@A*Y=qa%zHlDv^yWbR03%V0 zprLP+b(#fBqxI%FiF*-n8HtH6$8f(P6!H3V^ysgd8de-N(@|K!A< z^qP}jp(RaM9kQ(^K(U8O84?D)aU(g?1S8iWwe)gqpHCaFlJxb*ilr{KTnu4_@5{K- z)n=CCeCrPHO0WHz)dDtkbZfUfVBd?53}K>C5*-wC4hpDN8cGk3lu-ypq+EYpb_2H; z%vP4@&+c2p;thaTs$dc^1CDGlPG@A;yGR5@$UEqk6p58qpw#7lc<+W(WR;(vr(D>W z#(K$vE#uBkT=*q&uaZwzz=P5mjiee6>!lV?c}QIX%ZdkO1dHg>Fa#xcGT6~}1*2m9 zkc7l3ItD6Ie~o_aFjI$Ri=C!8uF4!Ky7iG9QTrxVbsQroi|r)SAon#*B*{}TB-?=@ z8~jJs;_R2iDd!$+n$%X6FO&PYS{YhDAS+U2o4su9x~1+U3z7YN5o0qUK&|g^klZ6X zj_vrM5SUTnz5`*}Hyts9ADwLu#x_L=nv$Z0`HqN`Zo=V>OQI)fh01n~*a%01%cx%0 z4LTFVjmW+ipVQv5rYcn3;d2o4qunWUY!p+?s~X~(ost@WR@r@EuDOSs8*MT4fiP>! zkfo^!PWJJ1MHgKS2D_hc?Bs?isSDO61>ebl$U*9*QY(b=i&rp3@3GV@z>KzcZOxip z^dzA~44;R~cnhWz7s$$v?_8y-k!DZys}Q?4IkSyR!)C0j$(Gm|t#e3|QAOFaV2}36 z?dPNY;@I=FaCwylc_;~kXlZsk$_eLkNb~TIl8QQ`mmH&$*zwwR8zHU*sId)rxHu*K z;yZWa8UmCwju%aSNLwD5fBl^b0Ux1%q8YR*uG`53Mi<`5uA^Dc6Ync)J3N7;zQ*75)hf%a@{$H+%S?SGT)ks60)?6j$ zspl|4Ad6@%-r1t*$tT(en!gIXTUDcsj?28ZEzz)dH)SV3bZ+pjMaW0oc~rOPZP@g! zb9E+ndeVO_Ib9c_>{)`01^`ZS198 z)(t=+{Azi11$eu%aU7jbwuQrO`vLOixuh~%4z@mKr_Oc;F%Uq01fA)^W&y+g16e?rkLhTxV!EqC%2}sx_1u7IBq|}Be&7WI z4I<;1-9tJsI&pQIhj>FPkQV9{(m!wYYV@i5h?A0#BN2wqlEwNDIq06|^2oYVa7<~h zI_OLan0Do*4R5P=a3H9`s5*>xU}_PSztg`+2mv)|3nIy=5#Z$%+@tZnr> zLcTI!Mxa`PY7%{;KW~!=;*t)R_sl<^b>eNO@w#fEt(tPMg_jpJpW$q_DoUlkY|uo> z0-1{ouA#;t%spf*7VjkK&$QrvwUERKt^Sdo)5@?qAP)>}Y!h4(JQ!7{wIdkA+|)bv z&8hBwoX4v|+fie}iTslaBX^i*TjwO}f{V)8*!dMmRPi%XAWc8<_IqK1jUsApk)+~R zNFTCD-h>M5Y{qTQ&0#j@I@tmXGj%rzhTW5%Bkh&sSc=$Fv;M@1y!zvYG5P2(2|(&W zlcbR1{--rJ&s!rB{G-sX5^PaM@3EqWVz_y9cwLR9xMig&9gq(voeI)W&{d6j1jh&< zARXi&APWE1FQWh7eoZjuP z;vdgX>zep^{{2%hem;e*gDJhK1Hj12nBLIJoL<=0+8SVEBx7!4Ea+hBY;A1gBwvY<)tj~T=H`^?3>zeWWm|LAwo*S4Z%bDVUe z6r)CH1H!(>OH#MXFJ2V(U(qxD{4Px2`8qfFLG+=a;B^~Te_Z!r3RO%Oc#ZAHKQxV5 zRYXxZ9T2A%NVJIu5Pu7!Mj>t%YDO$T@M=RR(~mi%sv(YXVl`yMLD;+WZ{vG9(@P#e zMo}ZiK^7^h6TV%cG+;jhJ0s>h&VERs=tuZz^Tlu~%d{ZHtq6hX$V9h)Bw|jVCMudd zwZ5l7In8NT)qEPGF$VSKg&fb0%R2RnUnqa){)V(X(s0U zkCdVZe6wy{+_WhZh3qLp245Y2RR$@g-!9PjJ&4~0cFSHMUn=>dapv)hy}|y91ZWTV zCh=z*!S3_?`$&-eZ6xIXUq8RGl9oK0BJw*TdU6A`LJqX9eS3X@F)g$jLkBWFscPhR zpCv8#KeAc^y>>Y$k^=r|K(DTC}T$0#jQBOwB#@`P6~*IuW_8JxCG}J4va{ zsZzt}tt+cv7=l&CEuVtjD6G2~_Meh%p4RGuY?hSt?(sreO_F}8r7Kp$qQdvCdZnDQ zxzc*qchE*E2=WK)^oRNa>Ttj`fpvF-JZ5tu5>X1xw)J@1!IqWjq)ESBG?J|ez`-Tc zi5a}GZx|w-h%5lNDE_3ho0hEXMoaofo#Z;$8|2;EDF&*L+e$u}K=u?pb;dv$SXeQM zD-~7P0i_`Wk$#YP$=hw3UVU+=^@Kuy$>6?~gIXx636jh{PHly_a2xNYe1l60`|y!7 z(u%;ILuW0DDJ)2%y`Zc~hOALnj1~txJtcdD#o4BCT68+8gZe`=^te6H_egxY#nZH&P*)hgYaoJ^qtmpeea`35Fw)cy!w@c#v6E29co8&D9CTCl%^GV|X;SpneSXzV~LXyRn-@K0Df z{tK-nDWA!q38M1~`xUIt_(MO^R(yNY#9@es9RQbY@Ia*xHhD&=k^T+ zJi@j2I|WcgW=PuAc>hs`(&CvgjL2a9Rx zCbZyUpi8NWUOi@S%t+Su4|r&UoU|ze9SVe7p@f1GBkrjkkq)T}X%Qo1g!SQ{O{P?m z-OfGyyWta+UCXH+-+(D^%kw#A1-U;?9129at7MeCCzC{DNgO zeSqsV>W^NIfTO~4({c}KUiuoH8A*J!Cb0*sp*w-Bg@YfBIPZFH!M}C=S=S7PLLcIG zs7K77g~W)~^|+mx9onzMm0qh(f~OsDTzVmRtz=aZTllgR zGUn~_5hw_k&rll<4G=G+`^Xlnw;jNYDJz@bE?|r866F2hA9v0-8=JO3g}IHB#b`hy zA42a0>{0L7CcabSD+F7?pGbS1KMvT{@1_@k!_+Ki|5~EMGt7T%u=79F)8xEiL5!EJ zzuxQ`NBliCoJMJdwu|);zRCD<5Sf?Y>U$trQ-;xj6!s5&w=9E7)%pZ+1Nh&8nCCwM zv5>Ket%I?cxr3vVva`YeR?dGxbG@pi{H#8@kFEf0Jq6~K4>kt26*bxv=P&jyE#e$| zDJB_~imk^-z|o!2njF2hL*|7sHCnzluhJjwLQGDmC)Y9 zr9ZN`s)uCd^XDvn)VirMgW~qfn1~SaN^7vcX#K1G`==UGaDVVx$0BQnubhX|{e z^i0}>k-;BP#Szk{cFjO{2x~LjK{^Upqd&<+03_iMLp0$!6_$@TbX>8U-f*-w-ew1?`CtD_0y_Lo|PfKi52p?`5$Jzx0E8`M0 zNIb?#!K$mM4X%`Ry_yhG5k@*+n4||2!~*+&pYLh~{`~o(W|o64^NrjP?-1Lgu?iK^ zTX6u3?#$?R?N!{599vg>G8RGHw)Hx&=|g4599y}mXNpM{EPKKXB&+m?==R3GsIq?G zL5fH={=zawB(sMlDBJ+{dgb)Vx3pu>L=mDV0{r1Qs{0Pn%TpopH{m(By4;{FBvi{I z$}x!Iw~MJOL~&)p93SDIfP3x%ROjg}X{Sme#hiJ&Yk&a;iR}V|n%PriZBY8SX2*;6 z4hdb^&h;Xz%)BDACY5AUsV!($lib4>11UmcgXKWpzRL8r2Srl*9Y(1uBQsY&hO&uv znDNff0tpHlLISam?o(lOp#CmFdH<6HmA0{UwfU#Y{8M+7od8b8|B|7ZYR9f<#+V|ZSaCQvI$~es~g(Pv{2&m_rKSB2QQ zMvT}$?Ll>V+!9Xh5^iy3?UG;dF-zh~RL#++roOCsW^cZ&({6q|?Jt6`?S8=16Y{oH zp50I7r1AC1(#{b`Aq5cw>ypNggHKM9vBx!W$eYIzD!4KbLsZGr2o8>g<@inmS3*>J zx8oG((8f!ei|M@JZB`p7+n<Q}?>h249<`7xJ?u}_n;Gq(&km#1ULN87CeTO~FY zS_Ty}0TgQhV zOh3T7{{x&LSYGQfKR1PDIkP!WnfC1$l+fs@Di+d4O=eVKeF~2fq#1<8hEvpwuqcaH z4A8u~r^gnY3u6}zj*RHjk{AHhrrDqaj?|6GaVJbV%o-nATw}ASFr!f`Oz|u_QPkR# z0mDudY1dZRlk@TyQ?%Eti=$_WNFtLpSx9=S^be{wXINp%MU?a`F66LNU<c;0&ngifmP9i;bj6&hdGMW^Kf8e6ZDXbQD&$QAAMo;OQ)G zW(qlHh;}!ZP)JKEjm$VZjTs@hk&4{?@+NADuYrr!R^cJzU{kGc1yB?;7mIyAWwhbeA_l_lw-iDVi7wcFurf5 z#Uw)A@a9fOf{D}AWE%<`s1L_AwpZ?F!Vac$LYkp<#A!!`XKaDC{A%)~K#5z6>Hv@V zBEqF(D5?@6r3Pwj$^krpPDCjB+UOszqUS;b2n>&iAFcw<*im2(b3|5u6SK!n9Sg4I z0KLcwA6{Mq?p%t>aW0W!PQ>iUeYvNjdKYqII!CE7SsS&Rj)eIw-K4jtI?II+0IdGq z2WT|L3RL?;GtGgt1LWfI4Ka`9dbZXc$TMJ~8#Juv@K^1RJN@yzdLS8$AJ(>g!U9`# zx}qr7JWlU+&m)VG*Se;rGisutS%!6yybi%B`bv|9rjS(xOUIvbNz5qtvC$_JYY+c& za*3*2$RUH8p%pSq>48xR)4qsp!Q7BEiJ*`^>^6INRbC@>+2q9?x(h0bpc>GaNFi$K zPH$6!#(~{8@0QZk=)QnM#I=bDx5vTvjm$f4K}%*s+((H2>tUTf==$wqyoI`oxI7>C z&>5fe)Yg)SmT)eA(|j@JYR1M%KixxC-Eceknf-;N=jJTwKvk#@|J^&5H0c+%KxHUI z6dQbwwVx3p?X<_VRVb2fStH?HH zFR@Mp=qX%#L3XL)+$PXKV|o|#DpHAoqvj6uQKe@M-mnhCSou7Dj4YuO6^*V`m)1lf z;)@e%1!Qg$10w8uEmz{ENb$^%u}B;J7sDd zump}onoD#!l=agcBR)iG!3AF0-63%@`K9G(CzKrm$VJ{v7^O9Ps7Zej|3m= zVXlR&yW6=Y%mD30G@|tf=yC7-#L!16Q=dq&@beWgaIL40k0n% z)QHrp2Jck#evLMM1RGt3WvQ936ZC9vEje0nFMfvmOHVI+&okB_K|l-;|4vW;qk>n~ z+|kk8#`K?x`q>`(f6A${wfw9Cx(^)~tX7<#TpxR#zYG2P+FY~mG{tnEkv~d6oUQA+ z&hNTL=~Y@rF`v-RZlts$nb$3(OL1&@Y11hhL9+zUb6)SP!;CD)^GUtUpCHBE`j1te zAGud@miCVFLk$fjsrcpjsadP__yj9iEZUW{Ll7PPi<$R;m1o!&Xdl~R_v0;oDX2z^!&8}zNGA}iYG|k zmehMd1%?R)u6R#<)B)1oe9TgYH5-CqUT8N7K-A-dm3hbm_W21p%8)H{O)xUlBVb+iUR}-v5dFaCyfSd zC6Bd7=N4A@+Bna=!-l|*_(nWGDpoyU>nH=}IOrLfS+-d40&(Wo*dDB9nQiA2Tse$R z;uq{`X7LLzP)%Y9aHa4YQ%H?htkWd3Owv&UYbr5NUDAH^<l@Z0Cx%`N+B*i!!1u>D8%;Qt1$ zE5O0{-`9gdDxZ!`0m}ywH!;c{oBfL-(BH<&SQ~smbcobU!j49O^f4&IIYh~f+hK*M zZwTp%{ZSAhMFj1qFaOA+3)p^gnXH^=)`NTYgTu!CLpEV2NF=~-`(}7p^Eof=@VUbd z_9U|8qF7Rueg&$qpSSkN%%%DpbV?8E8ivu@ensI0toJ7Eas^jyFReQ1JeY9plb^{m z&eQO)qPLZQ6O;FTr*aJq=$cMN)QlQO@G&%z?BKUs1&I^`lq>=QLODwa`(mFGC`0H< zOlc*|N?B5&!U6BuJvkL?s1&nsi$*5cCv7^j_*l&$-sBmRS85UIrE--7eD8Gr3^+o? zqG-Yl4S&E;>H>k^a0GdUI(|n1`ws@)1%sq2XBdK`mqrNq_b4N{#VpouCXLzNvjoFv zo9wMQ6l0+FT+?%N(ka*;%m~(?338bu32v26!{r)|w8J`EL|t$}TA4q_FJRX5 zCPa{hc_I(7TGE#@rO-(!$1H3N-C0{R$J=yPCXCtGk{4>=*B56JdXU9cQVwB`6~cQZ zf^qK21x_d>X%dT!!)CJQ3mlHA@ z{Prkgfs6=Tz%63$6Zr8CO0Ak3A)Cv#@BVKr&aiKG7RYxY$Yx>Bj#3gJk*~Ps-jc1l z;4nltQwwT4@Z)}Pb!3xM?+EW0qEKA)sqzw~!C6wd^{03-9aGf3Jmt=}w-*!yXupLf z;)>-7uvWN4Unn8b4kfIza-X=x*e4n5pU`HtgpFFd))s$C@#d>aUl3helLom+RYb&g zI7A9GXLRZPl}iQS*d$Azxg-VgcUr*lpLnbPKUV{QI|bsG{8bLG<%CF( zMoS4pRDtLVYOWG^@ox^h8xL~afW_9DcE#^1eEC1SVSb1BfDi^@g?#f6e%v~Aw>@w- zIY0k+2lGWNV|aA*e#`U3=+oBDmGeInfcL)>*!w|*;mWiKNG6wP6AW4-4imN!W)!hE zA02~S1*@Q`fD*+qX@f3!2yJX&6FsEfPditB%TWo3=HA;T3o2IrjS@9SSxv%{{7&4_ zdS#r4OU41~GYMiib#z#O;zohNbhJknrPPZS6sN$%HB=jUnlCO_w5Gw5EeE@KV>soy z2EZ?Y|4RQDDjt5y!WBlZ(8M)|HP<0YyG|D%RqD+K#e7-##o3IZxS^wQ5{Kbzb6h(i z#(wZ|^ei>8`%ta*!2tJzwMv+IFHLF`zTU8E^Mu!R*45_=ccqI};Zbyxw@U%a#2}%f zF>q?SrUa_a4H9l+uW8JHh2Oob>NyUwG=QH~-^ZebU*R@67DcXdz2{HVB4#@edz?B< z5!rQH3O0>A&ylROO%G^fimV*LX7>!%re{_Sm6N>S{+GW1LCnGImHRoF@csnFzn@P0 zM=jld0z%oz;j=>c7mMwzq$B^2mae7NiG}%>(wtmsDXkWk{?BeMpTrIt3Mizq?vRsf zi_WjNp+61uV(%gEU-Vf0;>~vcDhe(dzWdaf#4mH3o^v{0EWhj?E?$5v02sV@xL0l4 zX0_IMFtQ44PfWBbPYN#}qxa%=J%dlR{O!KyZvk^g5s?sTNycWYPJ^FK(nl3k?z-5t z39#hKrdO7V(@!TU)LAPY&ngnZ1MzLEeEiZznn7e-jLCy8LO zu^7_#z*%I-BjS#Pg-;zKWWqX-+Ly$T!4`vTe5ZOV0j?TJVA*2?*=82^GVlZIuH%9s zXiV&(T(QGHHah=s&7e|6y?g+XxZGmK55`wGV>@1U)Th&=JTgJq>4mI&Av2C z)w+kRoj_dA!;SfTfkgMPO>7Dw6&1*Hi1q?54Yng`JO&q->^CX21^PrU^JU#CJ_qhV zSG>afB%>2fx<~g8p=P8Yzxqc}s@>>{g7}F!;lCXvF#RV)^fyYb_)iKVCz1xEq=fJ| z0a7DMCK*FuP=NM*5h;*D`R4y$6cpW-E&-i{v`x=Jbk_xSn@2T3q!3HoAOB`@5Vg6) z{PW|@9o!e;v1jZ2{=Uw6S6o{g82x6g=k!)cFSC*oemHaVjg?VpEmtUuD2_J^A~$4* z3O7HsbA6wxw{TP5Kk)(Vm?gKo+_}11vbo{Tp_5x79P~#F)ahQXT)tSH5;;14?s)On zel1J>1x>+7;g1Iz2FRpnYz;sD0wG9Q!vuzE9yKi3@4a9Nh1!GGN?hA)!mZEnnHh&i zf?#ZEN2sFbf~kV;>K3UNj1&vFhc^sxgj8FCL4v>EOYL?2uuT`0eDH}R zmtUJMxVrV5H{L53hu3#qaWLUa#5zY?f5ozIn|PkMWNP%n zWB5!B0LZB0kLw$k39=!akkE9Q>F4j+q434jB4VmslQ;$ zKiO#FZ`p|dKS716jpcvR{QJkSNfDVhr2%~eHrW;fU45>>snr*S8Vik-5eN5k*c2Mp zyxvX&_cFbB6lODXznHHT|rsURe2!swomtrqc~w5 zymTM8!w`1{04CBprR!_F{5LB+2_SOuZN{b*!J~1ZiPpP-M;);!ce!rOPDLtgR@Ie1 zPreuqm4!H)hYePcW1WZ0Fyaqe%l}F~Orr)~+;mkS&pOhP5Ebb`cnUt!X_QhP4_4p( z8YKQCDKGIy>?WIFm3-}Br2-N`T&FOi?t)$hjphB9wOhBXU#Hb+zm&We_-O)s(wc`2 z8?VsvU;J>Ju7n}uUb3s1yPx_F*|FlAi=Ge=-kN?1;`~6szP%$3B0|8Sqp%ebM)F8v zADFrbeT0cgE>M0DMV@_Ze*GHM>q}wWMzt|GYC%}r{OXRG3Ij&<+nx9;4jE${Fj_r* z`{z1AW_6Myd)i6e0E-h&m{{CvzH=Xg!&(bLYgRMO_YVd8JU7W+7MuGWNE=4@OvP9+ zxi^vqS@5%+#gf*Z@RVyU9N1sO-(rY$24LGsg1>w>s6ST^@)|D9>cT50maXLUD{Fzf zt~tp{OSTEKg3ZSQyQQ5r51){%=?xlZ54*t1;Ow)zLe3i?8tD8YyY^k%M)e`V*r+vL zPqUf&m)U+zxps+NprxMHF{QSxv}>lE{JZETNk1&F+R~bp{_T$dbXL2UGnB|hgh*p4h$clt#6;NO~>zuyY@C-MD@)JCc5XrYOt`wW7! z_ti2hhZBMJNbn0O-uTxl_b6Hm313^fG@e;RrhIUK9@# z+DHGv_Ow$%S8D%RB}`doJjJy*aOa5mGHVHz0e0>>O_%+^56?IkA5eN+L1BVCp4~m=1eeL zb;#G!#^5G%6Mw}r1KnaKsLvJB%HZL)!3OxT{k$Yo-XrJ?|7{s4!H+S2o?N|^Z z)+?IE9H7h~Vxn5hTis^3wHYuOU84+bWd)cUKuHapq=&}WV#OxHpLab`NpwHm8LmOo zjri+!k;7j_?FP##CpM+pOVx*0wExEex z@`#)K<-ZrGyArK;a%Km`^+We|eT+#MygHOT6lXBmz`8|lyZOwL1+b+?Z$0OhMEp3R z&J=iRERpv~TC=p2-BYLC*?4 zxvPs9V@g=JT0>zky5Poj=fW_M!c)Xxz1<=&_ZcL=LMZJqlnO1P^xwGGW*Z+yTBvbV z-IFe6;(k1@$1;tS>{%pXZ_7w+i?N4A2=TXnGf=YhePg8bH8M|Lk-->+w8Y+FjZ;L=wSGwxfA`gqSn)f(XNuSm>6Y z@|#e-)I(PQ^G@N`%|_DZSb4_pkaEF0!-nqY+t#pyA>{9^*I-zw4SYA1_z2Bs$XGUZbGA;VeMo%CezHK0lO={L%G)dI-+8w?r9iexdoB{?l zbJ}C?huIhWXBVs7oo{!$lOTlvCLZ_KN1N+XJGuG$rh<^eUQIqcI7^pmqhBSaOKNRq zrx~w^?9C?*&rNwP_SPYmo;J-#!G|{`$JZK7DxsM3N^8iR4vvn>E4MU&Oe1DKJvLc~ zCT>KLZ1;t@My zRj_2hI^61T&LIz)S!+AQIV23n1>ng+LUvzv;xu!4;wpqb#EZz;F)BLUzT;8UA1x*6vJ zicB!3Mj03s*kGV{g`fpC?V^s(=JG-k1EMHbkdP4P*1^8p_TqO|;!Zr%GuP$8KLxuf z=pv*H;kzd;P|2`JmBt~h6|GxdU~@weK5O=X&5~w$HpfO}@l-T7@vTCxVOwCkoPQv8 z@aV_)I5HQtfs7^X=C03zYmH4m0S!V@JINm6#(JmZRHBD?T!m^DdiZJrhKpBcur2u1 zf9e4%k$$vcFopK5!CC`;ww(CKL~}mlxK_Pv!cOsFgVkNIghA2Au@)t6;Y3*2gK=5d z?|@1a)-(sQ%uFOmJ7v2iG&l&m^u&^6DJM#XzCrF%r>{2XKyxLD2rgWBD;i(!e4InDQBDg==^z;AzT2z~OmV0!?Z z0S9pX$+E;w3WN;v&NYT=+G8hf=6w0E1$0AOr61}eOvE8W1jX%>&Mjo7&!ulawgzLH zbcb+IF(s^3aj12WSi#pzIpijJJzkP?JzRawnxmNDSUR#7!29vHULCE<3Aa#be}ie~d|!V+ z%l~s9Odo$G&fH!t!+`rUT0T9DulF!Yq&BfQWFZV1L9D($r4H(}Gnf6k3^wa7g5|Ws zj7%d`!3(0bb55yhC6@Q{?H|2os{_F%o=;-h{@Yyyn*V7?{s%Grvpe!H^kl6tF4Zf5 z{Jv1~yZ*iIWL_9C*8pBMQArfJJ0d9Df6Kl#wa}7Xa#Ef_5B7=X}DzbQXVPfCwTO@9+@;A^Ti6il_C>g?A-GFwA0#U;t4;wOm-4oS})h z5&on>NAu67O?YCQr%7XIzY%LS4bha9*e*4bU4{lGCUmO2UQ2U)QOqClLo61Kx~3dI zmV3*(P6F_Tr-oP%x!0kTnnT?Ep5j;_IQ^pTRp=e8dmJtI4YgWd0}+b2=ATkOhgpXe z;jmw+FBLE}UIs4!&HflFr4)vMFOJ19W4f2^W(=2)F%TAL)+=F>IE$=e=@j-*bFLSg z)wf|uFQu+!=N-UzSef62u0-C8Zc7 zo6@F)c+nZA{H|+~7i$DCU0pL{0Ye|fKLuV^w!0Y^tT$isu%i1Iw&N|tX3kwFKJN(M zXS`k9js66o$r)x?TWL}Kxl`wUDUpwFx(w4Yk%49;$sgVvT~n8AgfG~HUcDt1TRo^s zdla@6heJB@JV z!vK;BUMznhzGK6PVtj0)GB=zTv6)Q9Yt@l#fv7>wKovLobMV-+(8)NJmyF8R zcB|_K7=FJGGn^X@JdFaat0uhKjp3>k#^&xE_}6NYNG?kgTp>2Iu?ElUjt4~E-?`Du z?mDCS9wbuS%fU?5BU@Ijx>1HG*N?gIP+<~xE4u=>H`8o((cS5M6@_OK%jSjFHirQK zN9@~NXFx*jS{<|bgSpC|SAnA@I)+GB=2W|JJChLI_mx+-J(mSJ!b)uUom6nH0#2^(L@JBlV#t zLl?j54s`Y3vE^c_3^Hl0TGu*tw_n?@HyO@ZrENxA+^!)OvUX28gDSF*xFtQzM$A+O zCG=n#6~r|3zt=8%GuG} z<#VCZ%2?3Q(Ad#Y7GMJ~{U3>E{5e@z6+rgZLX{Cxk^p-7dip^d29;2N1_mm4QkASo z-L`GWWPCq$uCo;X_BmGIpJFBlhl<8~EG{vOD1o|X$aB9KPhWO_cKiU*$HWEgtf=fn zsO%9bp~D2c@?*K9jVN@_vhR03>M_8h!_~%aN!Cnr?s-!;U3SVfmhRwk11A^8Ns`@KeE}+ zN$H}a1U6E;*j5&~Og!xHdfK5M<~xka)x-0N)K_&e7AjMz`toDzasH+^1bZlC!n()crk9kg@$(Y{wdKvbuUd04N^8}t1iOgsKF zGa%%XWx@WoVaNC1!|&{5ZbkopFre-Lu(LCE5HWZBoE#W@er9W<>R=^oYxBvypN#x3 zq#LC8&q)GFP=5^-bpHj?LW=)-g+3_)Ylps!3^YQ{9~O9&K)xgy zMkCWaApU-MI~e^cV{Je75Qr7eF%&_H)BvfyKL=gIA>;OSq(y z052BFz3E(Prg~09>|_Z@!qj}@;8yxnw+#Ej0?Rk<y}4ghbD569B{9hSFr*^ygZ zr6j7P#gtZh6tMk6?4V$*Jgz+#&ug;yOr>=qdI#9U&^am2qoh4Jy}H2%a|#Fs{E(5r z%!ijh;VuGA6)W)cJZx+;9Bp1LMUzN~x_8lQ#D3+sL{be-Jyeo@@dv7XguJ&S5vrH` z>QxOMWn7N-T!D@1(@4>ZlL^y5>m#0!HKovs12GRav4z!>p(1~xok8+_{| z#Ae4{9#NLh#Vj2&JuIn5$d6t@__`o}umFo(n0QxUtd2GKCyE+erwXY?`cm*h&^9*8 zJ+8x6fRZI-e$CRygofIQN^dWysCxgkyr{(_oBwwSRxZora1(%(aC!5BTtj^+YuevI zx?)H#(xlALUp6QJ!=l9N__$cxBZ5p&7;qD3PsXRFVd<({Kh+mShFWJNpy`N@ab7?9 zv5=klvCJ4bx|-pvOO2-+G)6O?$&)ncA#Urze2rlBfp#htudhx-NeRnJ@u%^_bfw4o z4|{b8SkPV3b>Wera1W(+N@p9H>dc6{cnkh-sgr?e%(YkWvK+0YXVwk0=d`)}*47*B z5JGkEdVix!w7-<%r0JF~`ZMMPe;f0EQHuYHxya`puazyph*ZSb1mJAt^k4549BfS; zK7~T&lRb=W{s&t`DJ$B}s-eH1&&-wEOH1KWsKn0a(ZI+G!v&W4A*cl>qAvUv6pbUR z#(f#EKV8~hk&8oayBz4vaswc(?qw1vn`yC zZQDl2PCB-&Uu@g9ZQHhO+v(W0bNig{-k0;;`+wM@#@J)8r?qOYs#&vUna8ILxN7S{ zp1s41KnR8miQJtJtOr|+qk}wrLt+N*z#5o`TmD1)E&QD(Vh&pjZJ_J*0!8dy_ z>^=@v=J)C`x&gjqAYu`}t^S=DFCtc0MkBU2zf|69?xW`Ck~(6zLD)gSE{7n~6w8j_ zoH&~$ED2k5-yRa0!r8fMRy z;QjBYUaUnpd}mf%iVFPR%Dg9!d>g`01m~>2s))`W|5!kc+_&Y>wD@@C9%>-lE`WB0 zOIf%FVD^cj#2hCkFgi-fgzIfOi+ya)MZK@IZhHT5FVEaSbv-oDDs0W)pA0&^nM0TW zmgJmd7b1R7b0a`UwWJYZXp4AJPteYLH>@M|xZFKwm!t3D3&q~av?i)WvAKHE{RqpD{{%OhYkK?47}+}` zrR2(Iv9bhVa;cDzJ%6ntcSbx7v7J@Y4x&+eWSKZ*eR7_=CVIUSB$^lfYe@g+p|LD{ zPSpQmxx@b$%d!05|H}WzBT4_cq?@~dvy<7s&QWtieJ9)hd4)$SZz}#H2UTi$CkFWW|I)v_-NjuH!VypONC=1`A=rm_jfzQ8Fu~1r8i{q-+S_j$ z#u^t&Xnfi5tZtl@^!fUJhx@~Cg0*vXMK}D{>|$#T*+mj(J_@c{jXBF|rm4-8%Z2o! z2z0o(4%8KljCm^>6HDK!{jI7p+RAPcty_~GZ~R_+=+UzZ0qzOwD=;YeZt*?3%UGdr z`c|BPE;yUbnyARUl&XWSNJ<+uRt%!xPF&K;(l$^JcA_CMH6)FZt{>6ah$|(9$2fc~ z=CD00uHM{qv;{Zk9FR0~u|3|Eiqv9?z2#^GqylT5>6JNZwKqKBzzQpKU2_pmtD;CT zi%Ktau!Y2Tldfu&b0UgmF(SSBID)15*r08eoUe#bT_K-G4VecJL2Pa=6D1K6({zj6 za(2Z{r!FY5W^y{qZ}08+h9f>EKd&PN90f}Sc0ejf%kB4+f#T8Q1=Pj=~#pi$U zp#5rMR%W25>k?<$;$x72pkLibu1N|jX4cWjD3q^Pk3js!uK6h7!dlvw24crL|MZs_ zb%Y%?Fyp0bY0HkG^XyS76Ts*|Giw{31LR~+WU5NejqfPr73Rp!xQ1mLgq@mdWncLy z%8}|nzS4P&`^;zAR-&nm5f;D-%yNQPwq4N7&yULM8bkttkD)hVU>h>t47`{8?n2&4 zjEfL}UEagLUYwdx0sB2QXGeRmL?sZ%J!XM`$@ODc2!y|2#7hys=b$LrGbvvjx`Iqi z&RDDm3YBrlKhl`O@%%&rhLWZ*ABFz2nHu7k~3@e4)kO3%$=?GEFUcCF=6-1n!x^vmu+Ai*amgXH+Rknl6U>#9w;A} zn2xanZSDu`4%%x}+~FG{Wbi1jo@wqBc5(5Xl~d0KW(^Iu(U3>WB@-(&vn_PJt9{1`e9Iic@+{VPc`vP776L*viP{wYB2Iff8hB%E3|o zGMOu)tJX!`qJ}ZPzq7>=`*9TmETN7xwU;^AmFZ-ckZjV5B2T09pYliaqGFY|X#E-8 z20b>y?(r-Fn5*WZ-GsK}4WM>@TTqsxvSYWL6>18q8Q`~JO1{vLND2wg@58OaU!EvT z1|o+f1mVXz2EKAbL!Q=QWQKDZpV|jznuJ}@-)1&cdo z^&~b4Mx{*1gurlH;Vhk5g_cM&6LOHS2 zRkLfO#HabR1JD4Vc2t828dCUG#DL}f5QDSBg?o)IYYi@_xVwR2w_ntlpAW0NWk$F1 z$If?*lP&Ka1oWfl!)1c3fl`g*lMW3JOn#)R1+tfwrs`aiFUgz3;XIJ>{QFxLCkK30 zNS-)#DON3yb!7LBHQJ$)4y%TN82DC2-9tOIqzhZ27@WY^<6}vXCWcR5iN{LN8{0u9 zNXayqD=G|e?O^*ms*4P?G%o@J1tN9_76e}E#66mr89%W_&w4n66~R;X_vWD(oArwj z4CpY`)_mH2FvDuxgT+akffhX0b_slJJ*?Jn3O3~moqu2Fs1oL*>7m=oVek2bnprnW zixkaIFU%+3XhNA@@9hyhFwqsH2bM|`P?G>i<-gy>NflhrN{$9?LZ1ynSE_Mj0rADF zhOz4FnK}wpLmQuV zgO4_Oz9GBu_NN>cPLA=`SP^$gxAnj;WjJnBi%Q1zg`*^cG;Q)#3Gv@c^j6L{arv>- zAW%8WrSAVY1sj$=umcAf#ZgC8UGZGoamK}hR7j6}i8#np8ruUlvgQ$j+AQglFsQQq zOjyHf22pxh9+h#n$21&$h?2uq0>C9P?P=Juw0|;oE~c$H{#RGfa>| zj)Iv&uOnaf@foiBJ}_;zyPHcZt1U~nOcNB{)og8Btv+;f@PIT*xz$x!G?u0Di$lo7 zOugtQ$Wx|C($fyJTZE1JvR~i7LP{ zbdIwqYghQAJi9p}V&$=*2Azev$6K@pyblphgpv8^9bN!?V}{BkC!o#bl&AP!3DAjM zmWFsvn2fKWCfjcAQmE+=c3Y7j@#7|{;;0f~PIodmq*;W9Fiak|gil6$w3%b_Pr6K_ zJEG@&!J%DgBZJDCMn^7mk`JV0&l07Bt`1ymM|;a)MOWz*bh2#d{i?SDe9IcHs7 zjCrnyQ*Y5GzIt}>`bD91o#~5H?4_nckAgotN{2%!?wsSl|LVmJht$uhGa+HiH>;av z8c?mcMYM7;mvWr6noUR{)gE!=i7cZUY7e;HXa221KkRoc2UB>s$Y(k%NzTSEr>W(u z<(4mcc)4rB_&bPzX*1?*ra%VF}P1nwiP5cykJ&W{!OTlz&Td0pOkVp+wc z@k=-Hg=()hNg=Q!Ub%`BONH{ z_=ZFgetj@)NvppAK2>8r!KAgi>#%*7;O-o9MOOfQjV-n@BX6;Xw;I`%HBkk20v`qoVd0)}L6_49y1IhR z_OS}+eto}OPVRn*?UHC{eGyFU7JkPz!+gX4P>?h3QOwGS63fv4D1*no^6PveUeE5% zlehjv_3_^j^C({a2&RSoVlOn71D8WwMu9@Nb@=E_>1R*ve3`#TF(NA0?d9IR_tm=P zOP-x;gS*vtyE1Cm zG0L?2nRUFj#aLr-R1fX*$sXhad)~xdA*=hF3zPZhha<2O$Ps+F07w*3#MTe?)T8|A!P!v+a|ot{|^$q(TX`35O{WI0RbU zCj?hgOv=Z)xV?F`@HKI11IKtT^ocP78cqHU!YS@cHI@{fPD?YXL)?sD~9thOAv4JM|K8OlQhPXgnevF=F7GKD2#sZW*d za}ma31wLm81IZxX(W#A9mBvLZr|PoLnP>S4BhpK8{YV_}C|p<)4#yO{#ISbco92^3 zv&kCE(q9Wi;9%7>>PQ!zSkM%qqqLZW7O`VXvcj;WcJ`2~v?ZTYB@$Q&^CTfvy?1r^ z;Cdi+PTtmQwHX_7Kz?r#1>D zS5lWU(Mw_$B&`ZPmqxpIvK<~fbXq?x20k1~9az-Q!uR78mCgRj*eQ>zh3c$W}>^+w^dIr-u{@s30J=)1zF8?Wn|H`GS<=>Om|DjzC{}Jt?{!fSJe*@$H zg>wFnlT)k#T?LslW zu$^7Uy~$SQ21cE?3Ijl+bLfuH^U5P^$@~*UY#|_`uvAIe(+wD2eF}z_y!pvomuVO; zS^9fbdv)pcm-B@CW|Upm<7s|0+$@@<&*>$a{aW+oJ%f+VMO<#wa)7n|JL5egEgoBv zl$BY(NQjE0#*nv=!kMnp&{2Le#30b)Ql2e!VkPLK*+{jv77H7)xG7&=aPHL7LK9ER z5lfHxBI5O{-3S?GU4X6$yVk>lFn;ApnwZybdC-GAvaznGW-lScIls-P?Km2mF>%B2 zkcrXTk+__hj-3f48U%|jX9*|Ps41U_cd>2QW81Lz9}%`mTDIhE)jYI$q$ma7Y-`>% z8=u+Oftgcj%~TU}3nP8&h7k+}$D-CCgS~wtWvM|UU77r^pUw3YCV80Ou*+bH0!mf0 zxzUq4ed6y>oYFz7+l18PGGzhB^pqSt)si=9M>~0(Bx9*5r~W7sa#w+_1TSj3Jn9mW zMuG9BxN=}4645Cpa#SVKjFst;9UUY@O<|wpnZk$kE+to^4!?0@?Cwr3(>!NjYbu?x z1!U-?0_O?k!NdM^-rIQ8p)%?M+2xkhltt*|l=%z2WFJhme7*2xD~@zk#`dQR$6Lmd zb3LOD4fdt$Cq>?1<%&Y^wTWX=eHQ49Xl_lFUA(YQYHGHhd}@!VpYHHm=(1-O=yfK#kKe|2Xc*9}?BDFN zD7FJM-AjVi)T~OG)hpSWqH>vlb41V#^G2B_EvYlWhDB{Z;Q9-0)ja(O+By`31=biA zG&Fs#5!%_mHi|E4Nm$;vVQ!*>=_F;ZC=1DTPB#CICS5fL2T3XmzyHu?bI;m7D4@#; ztr~;dGYwb?m^VebuULtS4lkC_7>KCS)F@)0OdxZIFZp@FM_pHnJes8YOvwB|++#G( z&dm*OP^cz95Wi15vh`Q+yB>R{8zqEhz5of>Po$9LNE{xS<)lg2*roP*sQ}3r3t<}; zPbDl{lk{pox~2(XY5=qg0z!W-x^PJ`VVtz$git7?)!h>`91&&hESZy1KCJ2nS^yMH z!=Q$eTyRi68rKxdDsdt+%J_&lapa{ds^HV9Ngp^YDvtq&-Xp}60B_w@Ma>_1TTC;^ zpbe!#gH}#fFLkNo#|`jcn?5LeUYto%==XBk6Ik0kc4$6Z+L3x^4=M6OI1=z5u#M%0 z0E`kevJEpJjvvN>+g`?gtnbo$@p4VumliZV3Z%CfXXB&wPS^5C+7of2tyVkMwNWBiTE2 z8CdPu3i{*vR-I(NY5syRR}I1TJOV@DJy-Xmvxn^IInF>Tx2e)eE9jVSz69$6T`M9-&om!T+I znia!ZWJRB28o_srWlAxtz4VVft8)cYloIoVF=pL zugnk@vFLXQ_^7;%hn9x;Vq?lzg7%CQR^c#S)Oc-8d=q_!2ZVH764V z!wDKSgP}BrVV6SfCLZnYe-7f;igDs9t+K*rbMAKsp9L$Kh<6Z;e7;xxced zn=FGY<}CUz31a2G}$Q(`_r~75PzM4l_({Hg&b@d8&jC}B?2<+ed`f#qMEWi z`gm!STV9E4sLaQX+sp5Nu9*;9g12naf5?=P9p@H@f}dxYprH+3ju)uDFt^V{G0APn zS;16Dk{*fm6&BCg#2vo?7cbkkI4R`S9SSEJ=#KBk3rl69SxnCnS#{*$!^T9UUmO#&XXKjHKBqLdt^3yVvu8yn|{ zZ#%1CP)8t-PAz(+_g?xyq;C2<9<5Yy<~C74Iw(y>uUL$+$mp(DRcCWbCKiGCZw@?_ zdomfp+C5xt;j5L@VfhF*xvZdXwA5pcdsG>G<8II-|1dhAgzS&KArcb0BD4ZZ#WfiEY{hkCq5%z9@f|!EwTm;UEjKJsUo696V>h zy##eXYX}GUu%t{Gql8vVZKkNhQeQ4C%n|RmxL4ee5$cgwlU+?V7a?(jI#&3wid+Kz5+x^G!bb#$q>QpR#BZ}Xo5UW^ zD&I`;?(a}Oys7-`I^|AkN?{XLZNa{@27Dv^s4pGowuyhHuXc zuctKG2x0{WCvg_sGN^n9myJ}&FXyGmUQnW7fR$=bj$AHR88-q$D!*8MNB{YvTTEyS zn22f@WMdvg5~o_2wkjItJN@?mDZ9UUlat2zCh(zVE=dGi$rjXF7&}*sxac^%HFD`Y zTM5D3u5x**{bW!68DL1A!s&$2XG@ytB~dX-?BF9U@XZABO`a|LM1X3HWCllgl0+uL z04S*PX$%|^WAq%jkzp~%9HyYIF{Ym?k)j3nMwPZ=hlCg9!G+t>tf0o|J2%t1 ztC+`((dUplgm3`+0JN~}&FRRJ3?l*>Y&TfjS>!ShS`*MwO{WIbAZR#<%M|4c4^dY8 z{Rh;-!qhY=dz5JthbWoovLY~jNaw>%tS4gHVlt5epV8ekXm#==Po$)}mh^u*cE>q7*kvX&gq)(AHoItMYH6^s6f(deNw%}1=7O~bTHSj1rm2|Cq+3M z93djjdomWCTCYu!3Slx2bZVy#CWDozNedIHbqa|otsUl+ut?>a;}OqPfQA05Yim_2 zs@^BjPoFHOYNc6VbNaR5QZfSMh2S*`BGwcHMM(1@w{-4jVqE8Eu0Bi%d!E*^Rj?cR z7qgxkINXZR)K^=fh{pc0DCKtrydVbVILI>@Y0!Jm>x-xM!gu%dehm?cC6ok_msDVA*J#{75%4IZt}X|tIVPReZS#aCvuHkZxc zHVMtUhT(wp09+w9j9eRqz~LtuSNi2rQx_QgQ(}jBt7NqyT&ma61ldD(s9x%@q~PQl zp6N*?=N$BtvjQ_xIT{+vhb1>{pM0Arde0!X-y))A4znDrVx8yrP3B1(7bKPE5jR@5 zwpzwT4cu~_qUG#zYMZ_!2Tkl9zP>M%cy>9Y(@&VoB84#%>amTAH{(hL4cDYt!^{8L z645F>BWO6QaFJ-{C-i|-d%j7#&7)$X7pv#%9J6da#9FB5KyDhkA+~)G0^87!^}AP>XaCSScr;kL;Z%RSPD2CgoJ;gpYT5&6NUK$86$T?jRH=w8nI9Z534O?5fk{kd z`(-t$8W|#$3>xoMfXvV^-A(Q~$8SKDE^!T;J+rQXP71XZ(kCCbP%bAQ1|%$%Ov9_a zyC`QP3uPvFoBqr_+$HenHklqyIr>PU_Fk5$2C+0eYy^~7U&(!B&&P2%7#mBUhM!z> z_B$Ko?{Pf6?)gpYs~N*y%-3!1>o-4;@1Zz9VQHh)j5U1aL-Hyu@1d?X;jtDBNk*vMXPn@ z+u@wxHN*{uHR!*g*4Xo&w;5A+=Pf9w#PeZ^x@UD?iQ&${K2c}UQgLRik-rKM#Y5rdDphdcNTF~cCX&9ViRP}`>L)QA4zNXeG)KXFzSDa6 zd^St;inY6J_i=5mcGTx4_^Ys`M3l%Q==f>{8S1LEHn{y(kbxn5g1ezt4CELqy)~TV6{;VW>O9?5^ ztcoxHRa0jQY7>wwHWcxA-BCwzsP>63Kt&3fy*n#Cha687CQurXaRQnf5wc9o8v7Rw zNwGr2fac;Wr-Ldehn7tF^(-gPJwPt@VR1f;AmKgxN&YPL;j=0^xKM{!wuU|^mh3NE zy35quf}MeL!PU;|{OW_x$TBothLylT-J>_x6p}B_jW1L>k)ps6n%7Rh z96mPkJIM0QFNYUM2H}YF5bs%@Chs6#pEnloQhEl?J-)es!(SoJpEPoMTdgA14-#mC zghayD-DJWtUu`TD8?4mR)w5E`^EHbsz2EjH5aQLYRcF{l7_Q5?CEEvzDo(zjh|BKg z3aJl_n#j&eFHsUw4~lxqnr!6NL*se)6H=A+T1e3xUJGQrd}oSPwSy5+$tt{2t5J5@(lFxl43amsARG74iyNC}uuS zd2$=(r6RdamdGx^eatX@F2D8?U23tDpR+Os?0Gq2&^dF+$9wiWf?=mDWfjo4LfRwL zI#SRV9iSz>XCSgEj!cW&9H-njJopYiYuq|2w<5R2!nZ27DyvU4UDrHpoNQZiGPkp@ z1$h4H46Zn~eqdj$pWrv;*t!rTYTfZ1_bdkZmVVIRC21YeU$iS-*XMNK`#p8Z_DJx| zk3Jssf^XP7v0X?MWFO{rACltn$^~q(M9rMYoVxG$15N;nP)A98k^m3CJx8>6}NrUd@wp-E#$Q0uUDQT5GoiK_R{ z<{`g;8s>UFLpbga#DAf%qbfi`WN1J@6IA~R!YBT}qp%V-j!ybkR{uY0X|x)gmzE0J z&)=eHPjBxJvrZSOmt|)hC+kIMI;qgOnuL3mbNR0g^<%|>9x7>{}>a2qYSZAGPt4it?8 zNcLc!Gy0>$jaU?}ZWxK78hbhzE+etM`67*-*x4DN>1_&{@5t7_c*n(qz>&K{Y?10s zXsw2&nQev#SUSd|D8w7ZD2>E<%g^; zV{yE_O}gq?Q|zL|jdqB^zcx7vo(^})QW?QKacx$yR zhG|XH|8$vDZNIfuxr-sYFR{^csEI*IM#_gd;9*C+SysUFejP0{{z7@P?1+&_o6=7V|EJLQun^XEMS)w(=@eMi5&bbH*a0f;iC~2J74V2DZIlLUHD&>mlug5+v z6xBN~8-ovZylyH&gG#ptYsNlT?-tzOh%V#Y33zlsJ{AIju`CjIgf$@gr8}JugRq^c zAVQ3;&uGaVlVw}SUSWnTkH_6DISN&k2QLMBe9YU=sA+WiX@z)FoSYX`^k@B!j;ZeC zf&**P?HQG6Rk98hZ*ozn6iS-dG}V>jQhb3?4NJB*2F?6N7Nd;EOOo;xR7acylLaLy z9)^lykX39d@8@I~iEVar4jmjjLWhR0d=EB@%I;FZM$rykBNN~jf>#WbH4U{MqhhF6 zU??@fSO~4EbU4MaeQ_UXQcFyO*Rae|VAPLYMJEU`Q_Q_%s2*>$#S^)&7er+&`9L=1 z4q4ao07Z2Vsa%(nP!kJ590YmvrWg+YrgXYs_lv&B5EcoD`%uL79WyYA$0>>qi6ov7 z%`ia~J^_l{p39EY zv>>b}Qs8vxsu&WcXEt8B#FD%L%ZpcVtY!rqVTHe;$p9rbb5O{^rFMB>auLn-^;s+-&P1#h~mf~YLg$8M9 zZ4#87;e-Y6x6QO<{McUzhy(%*6| z)`D~A(TJ$>+0H+mct(jfgL4x%^oC^T#u(bL)`E2tBI#V1kSikAWmOOYrO~#-cc_8! zCe|@1&mN2{*ceeiBldHCdrURk4>V}79_*TVP3aCyV*5n@jiNbOm+~EQ_}1#->_tI@ zqXv+jj2#8xJtW508rzFrYcJxoek@iW6SR@1%a%Bux&;>25%`j3UI`0DaUr7l79`B1 zqqUARhW1^h6=)6?;@v>xrZNM;t}{yY3P@|L}ey@gG( z9r{}WoYN(9TW&dE2dEJIXkyHA4&pU6ki=rx&l2{DLGbVmg4%3Dlfvn!GB>EVaY_%3+Df{fBiqJV>~Xf8A0aqUjgpa} zoF8YXO&^_x*Ej}nw-$-F@(ddB>%RWoPUj?p8U{t0=n>gAI83y<9Ce@Q#3&(soJ{64 z37@Vij1}5fmzAuIUnXX`EYe;!H-yTVTmhAy;y8VZeB#vD{vw9~P#DiFiKQ|kWwGFZ z=jK;JX*A;Jr{#x?n8XUOLS;C%f|zj-7vXtlf_DtP7bpurBeX%Hjwr z4lI-2TdFpzkjgiv!8Vfv`=SP+s=^i3+N~1ELNWUbH|ytVu>EyPN_3(4TM^QE1swRo zoV7Y_g)a>28+hZG0e7g%@2^s>pzR4^fzR-El}ARTmtu!zjZLuX%>#OoU3}|rFjJg} zQ2TmaygxJ#sbHVyiA5KE+yH0LREWr%^C*yR|@gM$nK2P zo}M}PV0v))uJh&33N>#aU376@ZH79u(Yw`EQ2hM3SJs9f99+cO6_pNW$j$L-CtAfe zYfM)ccwD!P%LiBk!eCD?fHCGvgMQ%Q2oT_gmf?OY=A>&PaZQOq4eT=lwbaf}33LCH zFD|)lu{K7$8n9gX#w4~URjZxWm@wlH%oL#G|I~Fb-v^0L0TWu+`B+ZG!yII)w05DU z>GO?n(TN+B=>HdxVDSlIH76pta$_LhbBg;eZ`M7OGcqt||qi zogS72W1IN%=)5JCyOHWoFP7pOFK0L*OAh=i%&VW&4^LF@R;+K)t^S!96?}^+5QBIs zjJNTCh)?)4k^H^g1&jc>gysM`y^8Rm3qsvkr$9AeWwYpa$b22=yAd1t<*{ zaowSEFP+{y?Ob}8&cwfqoy4Pb9IA~VnM3u!trIK$&&0Op#Ql4j>(EW?UNUv#*iH1$ z^j>+W{afcd`{e&`-A{g}{JnIzYib)!T56IT@YEs{4|`sMpW3c8@UCoIJv`XsAw!XC z34|Il$LpW}CIHFC5e*)}00I5{%OL*WZRGzC0?_}-9{#ue?-ug^ zLE|uv-~6xnSs_2_&CN9{9vyc!Xgtn36_g^wI0C4s0s^;8+p?|mm;Odt3`2ZjwtK;l zfd6j)*Fr#53>C6Y8(N5?$H0ma;BCF3HCjUs7rpb2Kf*x3Xcj#O8mvs#&33i+McX zQpBxD8!O{5Y8D&0*QjD=Yhl9%M0)&_vk}bmN_Ud^BPN;H=U^bn&(csl-pkA+GyY0Z zKV7sU_4n;}uR78ouo8O%g*V;79KY?3d>k6%gpcmQsKk&@Vkw9yna_3asGt`0Hmj59 z%0yiF*`jXhByBI9QsD=+>big5{)BGe&+U2gAARGe3ID)xrid~QN_{I>k}@tzL!Md_ z&=7>TWciblF@EMC3t4-WX{?!m!G6$M$1S?NzF*2KHMP3Go4=#ZHkeIv{eEd;s-yD# z_jU^Ba06TZqvV|Yd;Z_sN%$X=!T+&?#p+OQIHS%!LO`Hx0q_Y0MyGYFNoM{W;&@0@ zLM^!X4KhdtsET5G<0+|q0oqVXMW~-7LW9Bg}=E$YtNh1#1D^6Mz(V9?2g~I1( zoz9Cz=8Hw98zVLwC2AQvp@pBeKyidn6Xu0-1SY1((^Hu*-!HxFUPs)yJ+i`^BC>PC zjwd0mygOVK#d2pRC9LxqGc6;Ui>f{YW9Bvb>33bp^NcnZoH~w9(lM5@JiIlfa-6|k ziy31UoMN%fvQfhi8^T+=yrP{QEyb-jK~>$A4SZT-N56NYEbpvO&yUme&pWKs3^94D zH{oXnUTb3T@H+RgzML*lejx`WAyw*?K7B-I(VJx($2!NXYm%3`=F~TbLv3H<{>D?A zJo-FDYdSA-(Y%;4KUP2SpHKAIcv9-ld(UEJE7=TKp|Gryn;72?0LHqAN^fk6%8PCW z{g_-t)G5uCIf0I`*F0ZNl)Z>))MaLMpXgqWgj-y;R+@A+AzDjsTqw2Mo9ULKA3c70 z!7SOkMtZb+MStH>9MnvNV0G;pwSW9HgP+`tg}e{ij0H6Zt5zJ7iw`hEnvye!XbA@!~#%vIkzowCOvq5I5@$3wtc*w2R$7!$*?}vg4;eDyJ_1=ixJuEp3pUS27W?qq(P^8$_lU!mRChT}ctvZz4p!X^ zOSp|JOAi~f?UkwH#9k{0smZ7-#=lK6X3OFEMl7%)WIcHb=#ZN$L=aD`#DZKOG4p4r zwlQ~XDZ`R-RbF&hZZhu3(67kggsM-F4Y_tI^PH8PMJRcs7NS9ogF+?bZB*fcpJ z=LTM4W=N9yepVvTj&Hu~0?*vR1HgtEvf8w%Q;U0^`2@e8{SwgX5d(cQ|1(!|i$km! zvY03MK}j`sff;*-%mN~ST>xU$6Bu?*Hm%l@0dk;j@%>}jsgDcQ)Hn*UfuThz9(ww_ zasV`rSrp_^bp-0sx>i35FzJwA!d6cZ5#5#nr@GcPEjNnFHIrtUYm1^Z$;{d&{hQV9 z6EfFHaIS}46p^5I-D_EcwwzUUuO}mqRh&T7r9sfw`)G^Q%oHxEs~+XoM?8e*{-&!7 z7$m$lg9t9KP9282eke608^Q2E%H-xm|oJ8=*SyEo} z@&;TQ3K)jgspgKHyGiKVMCz>xmC=H5Fy3!=TP)-R3|&1S-B)!6q50wfLHKM@7Bq6E z44CY%G;GY>tC`~yh!qv~YdXw! zSkquvYNs6k1r7>Eza?Vkkxo6XRS$W7EzL&A`o>=$HXgBp{L(i^$}t`NcnAxzbH8Ht z2!;`bhKIh`f1hIFcI5bHI=ueKdzmB9)!z$s-BT4ItyY|NaA_+o=jO%MU5as9 zc2)aLP>N%u>wlaXTK!p)r?+~)L+0eCGb5{8WIk7K52$nufnQ+m8YF+GQc&{^(zh-$ z#wyWV*Zh@d!b(WwXqvfhQX)^aoHTBkc;4ossV3&Ut*k>AI|m+{#kh4B!`3*<)EJVj zwrxK>99v^k4&Y&`Awm>|exo}NvewV%E+@vOc>5>%H#BK9uaE2$vje zWYM5fKuOTtn96B_2~~!xJPIcXF>E_;yO8AwpJ4)V`Hht#wbO3Ung~@c%%=FX4)q+9 z99#>VC2!4l`~0WHs9FI$Nz+abUq# zz`Of97})Su=^rGp2S$)7N3rQCj#0%2YO<R&p>$<#lgXcUj=4H_{oAYiT3 z44*xDn-$wEzRw7#@6aD)EGO$0{!C5Z^7#yl1o;k0PhN=aVUQu~eTQ^Xy{z8Ow6tk83 z4{5xe%(hx)%nD&|e*6sTWH`4W&U!Jae#U4TnICheJmsw{l|CH?UA{a6?2GNgpZLyzU2UlFu1ZVwlALmh_DOs03J^Cjh1im`E3?9&zvNmg(MuMw&0^Lu$(#CJ*q6DjlKsY-RMJ^8yIY|{SQZ*9~CH|u9L z`R78^r=EbbR*_>5?-)I+$6i}G)%mN(`!X72KaV(MNUP7Nv3MS9S|Pe!%N2AeOt5zG zVJ;jI4HZ$W->Ai_4X+`9c(~m=@ek*m`ZQbv3ryI-AD#AH=`x$~WeW~M{Js57(K7(v ze5`};LG|%C_tmd>bkufMWmAo&B+DT9ZV~h(4jg0>^aeAqL`PEUzJJtI8W1M!bQWpv zvN(d}E1@nlYa!L!!A*RN!(Q3F%J?5PvQ0udu?q-T)j3JKV~NL>KRb~w-lWc685uS6 z=S#aR&B8Sc8>cGJ!!--?kwsJTUUm`Jk?7`H z7PrO~xgBrSW2_tTlCq1LH8*!o?pj?qxy8}(=r_;G18POrFh#;buWR0qU24+XUaVZ0 z?(sXcr@-YqvkCmHr{U2oPogHL{r#3r49TeR<{SJX1pcUqyWPrkYz^X8#QW~?F)R5i z>p^!i<;qM8Nf{-fd6!_&V*e_9qP6q(s<--&1Ttj01j0w>bXY7y1W*%Auu&p|XSOH=)V7Bd4fUKh&T1)@cvqhuD-d=?w}O zjI%i(f|thk0Go*!d7D%0^ztBfE*V=(ZIN84f5HU}T9?ulmEYzT5usi=DeuI*d|;M~ zp_=Cx^!4k#=m_qSPBr5EK~E?3J{dWWPH&oCcNepYVqL?nh4D5ynfWip$m*YlZ8r^Z zuFEUL-nW!3qjRCLIWPT0x)FDL7>Yt7@8dA?R2kF@WE>ysMY+)lTsgNM#3VbXVGL}F z1O(>q>2a+_`6r5Xv$NZAnp=Kgnr3)cL(^=8ypEeOf3q8(HGe@7Tt59;yFl||w|mnO zHDxg2G3z8=(6wjj9kbcEY@Z0iOd7Gq5GiPS5% z*sF1J<#daxDV2Z8H>wxOF<;yKzMeTaSOp_|XkS9Sfn6Mpe9UBi1cSTieGG5$O;ZLIIJ60Y>SN4vC?=yE_CWlo(EEE$e4j?z&^FM%kNmRtlbEL^dPPgvs9sbK5fGw*r@ z+!EU@u$T8!nZh?Fdf_qk$VuHk^yVw`h`_#KoS*N%epIIOfQUy_&V}VWDGp3tplMbf z5Se1sJUC$7N0F1-9jdV2mmGK{-}fu|Nv;12jDy0<-kf^AmkDnu6j~TPWOgy1MT68|D z=4=50jVbUKdKaQgD`eWGr3I&^<6uhkjz$YwItY8%Yp9{z4-{6g{73<_b*@XJ4Nm3-3z z?BW3{aY_ccRjb@W1)i5nLg|7BnWS!B`_Uo9CWaE`Ij327QH?i)9A}4Ug4wmxVVa^b z-4+m%-wwOl7cKH7+=x&nrCrbEC)Q$fpg&V83#uEH;C=GNMz`ps@^RxK%T*8%OPnC` z{WO~J%nxYJ`x|N%?&i7?;{_8t^jM&=50HlaOQj8fS}_`moH$c;vI<|cruPFnpT8yU zS%rPOCUSd5Zdb(zwk`hqwTQn)*&n)uYsP*F_(~xEWq}C= zv30kFmZFwJZ@ELVX3?$dXQh|icO7UrL*_5G=I^xXjImz`ZPp>?g#tf(ej~KaIU0algsG!IS09;>?MvqGg#c{i+}qY|{P8W~O%#>|gFd z<1dr$-oxyRGN17yZo1OwLnzwYs0|;IS_nymNB0IlSzPQ%-r`?T=;_XQ^~&#}b|AB} zkNbN5uB?-sUB-T5QLlg%Uk3)uHB;>VIzGe9_J9 zaeISkQm!v(9d(0ML^b9fR^sfHFlH?7Mvddt37OuR{|O0{uv)(&-6<87W4 zyO>s!=cPgP3O&7xxU5DlIPw_o3O>6o6Qb?JWs3qw#p3sBc3g$?Dx zi(6D+DYgV;GrUis-CL%Qe{nvZnwaVXmbhH(|GFh|Q)k=1uvA$I@1DXI7bKlQ@8D6P zS?(*?><>)G49q0wr;NajpxP4W2G)kHl6^=Z>hrNEI4Mwd_$O6$1dXF;Q#hE(-eeW6 zz03GJF%Wl?HO=_ztv5*zRlcU~{+{k%#N59mgm~eK>P!QZ6E?#Cu^2)+K8m@ySvZ*5 z|HDT}BkF@3!l(0%75G=1u2hETXEj!^1Z$!)!lyGXlWD!_vqGE$Z)#cUVBqlORW>0^ zDjyVTxwKHKG|0}j-`;!R-p>}qQfBl(?($7pP<+Y8QE#M8SCDq~k<+>Q^Zf@cT_WdX3~BSe z+|KK|7OL5Hm5(NFP~j>Ct3*$wi0n0!xl=(C61`q&cec@mFlH(sy%+RH<=s)8aAPN`SfJdkAQjdv82G5iRdv8 zh{9wHUZaniSEpslXl^_ODh}mypC?b*9FzLjb~H@3DFSe;D(A-K3t3eOTB(m~I6C;(-lKAvit(70k`%@+O*Ztdz;}|_TS~B?Tpmi=QKC^m_ z2YpEaT3iiz*;T~ap1yiA)a`dKMwu`^UhIUeltNQ1Yjo=q@bI@&3zH?rVUg=IxLy-ni zyxDu%-Fr{H6owTjZU2O5>nDb=q&Jz_TjeSq%!2m40x&U6w~GQ({quPL73IsJS;f`$ zsuhioqCBj(gJ>2hoo)Gou7(WP*pX)f=Y=!=k!&1K?EYY%jJ~X&DnK{^saPQK<1BJ z_A`_{%ZozcB(3w$z^To^6d|XuT@=X~wtW!+{4ID@N{AB~J6AL5vuY>JwvWCNFKsKh zd}@>q@_WV#QZ&UJ0#?X(pXR!oyXOEG3rqzHbCzGLONDb042i$})fM@XF)uSP(DHUc z^&{|$*xe{cs?Gp8=B%RY3L7#$ve$?TWh>MZdxF1zH1v}1z+$Ov#G7?%D)bBCyDe*% zSeKSpETC2V1){II>@UwJi>4uBN+iAx+82E~gb|Cr&8E^i&)A!uv-g?jzH99wU}8+# z$nh>yvb;TwZmS@7LrvuCu_d0-WxFNI&C7%sWuTL%YU!l|I1{|->=dlOeHOCtUO#zkS3ESO8LHV4hTdQL5EdV zuWD33fFPH}HPrW^s$Qn1Xgp&AT6<-He{{4%eIu3rN=iK|9mURdKXfB&Q?qGok%!cs ze53UP{Z!TO-Y@q2;;k2avA3`lm4OoN4@S*k=UA)7H;qZ`d8`XaYFCv?Ba+uGW@r5v z&&{nf(24WSBOhc7!qF^@0cz;XcUynNaj6w2349;s!K{KVqs5yS{ z7VubS`2OzT^5#1~6Tt^RTvt9-J|D2F>y~>2;jeF>g`hx5l%B3H=aLExQihuYngzlnBTYOTHJQMzl>kwqN5JYs)Ej zblA@ntkUS~xi+}y6|(81helS}Q~&VB37qyV|S3Y=><^1wh%msQM?fz z<58MX(=|PSUKCF#)dbhR%D&xgCD?$aR0qen+wpp6 zst}vX18!Be96TD??j1HsHTUx(a&@F?=gT`Q$oJFFyrh^;zgz!(NlAHGn0cJy@us=w zNhC#l5G;H}+>49Nsh12=ZPO2r*2OBQe5kpb&1?*PIBFitK8}FUfb~S-#hKfF0o#&d z#3aPkB$9scYku&kA6{0xHnBV#&Wei5J>5T-XX-gUXEPo+9b7WL=*XESc(3BshL`aj zXp}QIp*40}oWJt*l043e8_5;H5PI5c)U&IEw5dF(4zjX0y_lk9 zAp@!mK>WUqHo)-jop=DoK>&no>kAD=^qIE7qis&_*4~ z6q^EF$D@R~3_xseCG>Ikb6Gfofb$g|75PPyyZN&tiRxqovo_k zO|HA|sgy#B<32gyU9x^&)H$1jvw@qp+1b(eGAb)O%O!&pyX@^nQd^9BQ4{(F8<}|A zhF&)xusQhtoXOOhic=8#Xtt5&slLia3c*a?dIeczyTbC#>FTfiLST57nc3@Y#v_Eg#VUv zT8cKH#f3=1PNj!Oroz_MAR*pow%Y0*6YCYmUy^7`^r|j23Q~^*TW#cU7CHf0eAD_0 zEWEVddxFgQ7=!nEBQ|ibaScslvhuUk^*%b#QUNrEB{3PG@uTxNwW}Bs4$nS9wc(~O zG7Iq>aMsYkcr!9#A;HNsJrwTDYkK8ikdj{M;N$sN6BqJ<8~z>T20{J8Z2rRUuH7~3 z=tgS`AgxbBOMg87UT4Lwge`*Y=01Dvk>)^{Iu+n6fuVX4%}>?3czOGR$0 zpp*wp>bsFFSV`V;r_m+TZns$ZprIi`OUMhe^cLE$2O+pP3nP!YB$ry}2THx2QJs3< za1;>d-AggCarrQ>&Z!d@;mW+!q6eXhb&`GbzUDSxpl8AJ#Cm#tuc)_xh(2NV=5XMs zrf_ozRYO$NkC=pKFX5OH8v1>0i9Z$ec`~Mf+_jQ68spn(CJwclDhEEkH2Qw;${J$clv__nUjn5jA0wCLEnu1j;v!0vB>Ri6m9`;R{JMS%^)4FC zU0Z44+u$I$w=Bj|iu4DT5h~sS`C*zbmX?@-crY}E+hy>}2~C0Nn(EKk@5^qO4@l@! z6O0lr%tzGC`D^)8xU3FnMZVm0kX1sBWhaQyzVoXFWwr%Ny?=2M{5s#5i7fTu3gEkG zc{(Pr$v=;`Y#&`y*J}#M9ux>0?xu!`$9cUKm#Bdd_&S#LPTS?ZPV6zN6>W6JTS~-LfjL{mB=b(KMk3 z2HjBSlJeyUVqDd=Mt!=hpYsvby2GL&3~zm;0{^nZJq+4vb?5HH4wufvr}IX42sHeK zm@x?HN$8TsTavXs)tLDFJtY9b)y~Tl@7z4^I8oUQq4JckH@~CVQ;FoK(+e0XAM>1O z(ei}h?)JQp>)d=6ng-BZF1Z5hsAKW@mXq+hU?r8I(*%`tnIIOXw7V6ZK(T9RFJJe@ zZS!aC+p)Gf2Ujc=a6hx4!A1Th%YH!Lb^xpI!Eu` zmJO{9rw){B1Ql18d%F%da+Tbu1()?o(zT7StYqK6_w`e+fjXq5L^y(0 z09QA6H4oFj59c2wR~{~>jUoDzDdKz}5#onYPJRwa`SUO)Pd4)?(ENBaFVLJr6Kvz= zhTtXqbx09C1z~~iZt;g^9_2nCZ{};-b4dQJbv8HsWHXPVg^@(*!@xycp#R?a|L!+` zY5w))JWV`Gls(=}shH0#r*;~>_+-P5Qc978+QUd>J%`fyn{*TsiG-dWMiJXNgwBaT zJ=wgYFt+1ACW)XwtNx)Q9tA2LPoB&DkL16P)ERWQlY4%Y`-5aM9mZ{eKPUgI!~J3Z zkMd5A_p&v?V-o-6TUa8BndiX?ooviev(DKw=*bBVOW|=zps9=Yl|-R5@yJe*BPzN}a0mUsLn{4LfjB_oxpv(mwq# zSY*%E{iB)sNvWfzg-B!R!|+x(Q|b@>{-~cFvdDHA{F2sFGA5QGiIWy#3?P2JIpPKg6ncI^)dvqe`_|N=8InKkE~^UnAEs2gk5 zUVGPCwX3dOb!}xiFmPB95NK!+5D<~S0s;d1zn&lrfAn7 zC?Nb-LFlib|DTEqB8oDS5&$(u1<5;wsY!V`2F7^=IR@I9so5q~=3i_(hqqG<9SbL8Q(LqDrz+aNtGYWGJ2;p*{a-^;C>BfGzkz_@fPsK8{pTT~_VzB$E`P@> z7+V1WF2+tSW=`ZRj3&0m&d#x_lfXq`bb-Y-SC-O{dkN2EVM7@!n|{s+2=xSEMtW7( zz~A!cBpDMpQu{FP=y;sO4Le}Z)I$wuFwpugEY3vEGfVAHGqZ-<{vaMv-5_^uO%a{n zE_Zw46^M|0*dZ`;t%^3C19hr=8FvVdDp1>SY>KvG!UfD`O_@weQH~;~W=fXK_!Yc> z`EY^PDJ&C&7LC;CgQJeXH2 zjfM}2(1i5Syj)Jj4EaRyiIl#@&lC5xD{8hS4Wko7>J)6AYPC-(ROpVE-;|Z&u(o=X z2j!*>XJ|>Lo+8T?PQm;SH_St1wxQPz)b)Z^C(KDEN$|-6{A>P7r4J1R-=R7|FX*@! zmA{Ja?XE;AvisJy6;cr9Q5ovphdXR{gE_7EF`ji;n|RokAJ30Zo5;|v!xtJr+}qbW zY!NI6_Wk#6pWFX~t$rAUWi?bAOv-oL6N#1>C~S|7_e4 zF}b9(&a*gHk+4@J26&xpiWYf2HN>P;4p|TD4f586umA2t@cO1=Fx+qd@1Ae#Le>{-?m!PnbuF->g3u)7(n^llJfVI%Q2rMvetfV5 z6g|sGf}pV)3_`$QiKQnqQ<&ghOWz4_{`rA1+7*M0X{y(+?$|{n zs;FEW>YzUWg{sO*+D2l6&qd+$JJP_1Tm;To<@ZE%5iug8vCN3yH{!6u5Hm=#3HJ6J zmS(4nG@PI^7l6AW+cWAo9sFmE`VRcM`sP7X$^vQY(NBqBYU8B|n-PrZdNv8?K?kUTT3|IE`-A8V*eEM2=u*kDhhKsmVPWGns z8QvBk=BPjvu!QLtlF0qW(k+4i+?H&L*qf262G#fks9}D5-L{yiaD10~a;-j!p!>5K zl@Lh+(9D{ePo_S4F&QXv|q_yT`GIPEWNHDD8KEcF*2DdZD;=J6u z|8ICSoT~5Wd!>g%2ovFh`!lTZhAwpIbtchDc{$N%<~e$E<7GWsD42UdJh1fD($89f2on`W`9XZJmr*7lRjAA8K0!(t8-u>2H*xn5cy1EG{J;w;Q-H8Yyx+WW(qoZZM7p(KQx^2-yI6Sw?k<=lVOVwYn zY*eDm%~=|`c{tUupZ^oNwIr!o9T;H3Fr|>NE#By8SvHb&#;cyBmY1LwdXqZwi;qn8 zK+&z{{95(SOPXAl%EdJ3jC5yV^|^}nOT@M0)|$iOcq8G{#*OH7=DlfOb; z#tRO#tcrc*yQB5!{l5AF3(U4>e}nEvkoE_XCX=a3&A6Atwnr&`r&f2d%lDr8f?hBB zr1dKNypE$CFbT9I?n){q<1zHmY>C=5>9_phi79pLJG)f=#dKdQ7We8emMjwR*qIMF zE_P-T*$hX#FUa%bjv4Vm=;oxxv`B*`weqUn}K=^TXjJG=UxdFMSj-QV6fu~;- z|IsUq`#|73M%Yn;VHJUbt<0UHRzbaF{X@76=8*-IRx~bYgSf*H(t?KH=?D@wk*E{| z2@U%jKlmf~C^YxD=|&H?(g~R9-jzEb^y|N5d`p#2-@?BUcHys({pUz4Zto7XwKq2X zSB~|KQGgv_Mh@M!*{nl~2~VV_te&E7K39|WYH zCxfd|v_4!h$Ps2@atm+gj14Ru)DhivY&(e_`eA)!O1>nkGq|F-#-6oo5|XKEfF4hR z%{U%ar7Z8~B!foCd_VRHr;Z1c0Et~y8>ZyVVo9>LLi(qb^bxVkbq-Jq9IF7!FT`(- zTMrf6I*|SIznJLRtlP)_7tQ>J`Um>@pP=TSfaPB(bto$G1C zx#z0$=zNpP-~R);kM4O)9Mqn@5Myv5MmmXOJln312kq#_94)bpSd%fcEo7cD#&|<` zrcal$(1Xv(nDEquG#`{&9Ci~W)-zd_HbH-@2F6+|a4v}P!w!Q*h$#Zu+EcZeY>u&?hn#DCfC zVuye5@Ygr+T)0O2R1*Hvlt>%rez)P2wS}N-i{~IQItGZkp&aeY^;>^m7JT|O^{`78 z$KaK0quwcajja;LU%N|{`2o&QH@u%jtH+j!haGj;*ZCR*`UgOXWE>qpXqHc?g&vA& zt-?_g8k%ZS|D;()0Lf!>7KzTSo-8hUh%OA~i76HKRLudaNiwo*E9HxmzN4y>YpZNO zUE%Q|H_R_UmX=*f=2g=xyP)l-DP}kB@PX|(Ye$NOGN{h+fI6HVw`~Cd0cKqO;s6aiYLy7sl~%gs`~XaL z^KrZ9QeRA{O*#iNmB7_P!=*^pZiJ5O@iE&X2UmUCPz!)`2G3)5;H?d~3#P|)O(OQ_ zua+ZzwWGkWflk4j^Lb=x56M75_p9M*Q50#(+!aT01y80x#rs9##!;b-BH?2Fu&vx} za%4!~GAEDsB54X9wCF~juV@aU}fp_(a<`Ig0Pip8IjpRe#BR?-niYcz@jI+QY zBU9!8dAfq@%p;FX)X=E7?B=qJJNXlJ&7FBsz;4&|*z{^kEE!XbA)(G_O6I9GVzMAF z8)+Un(6od`W7O!!M=0Z)AJuNyN8q>jNaOdC-zAZ31$Iq%{c_SYZe+(~_R`a@ zOFiE*&*o5XG;~UjsuW*ja-0}}rJdd@^VnQD!z2O~+k-OSF%?hqcFPa4e{mV1UOY#J zTf!PM=KMNAzbf(+|AL%K~$ahX0Ol zbAxKu3;v#P{Qia{_WzHl`!@!8c#62XSegM{tW1nu?Ee{sQq(t{0TSq67YfG;KrZ$n z*$S-+R2G?aa*6kRiTvVxqgUhJ{ASSgtepG3hb<3hlM|r>Hr~v_DQ>|Nc%&)r0A9go z&F3Ao!PWKVq~aWOzLQIy&R*xo>}{UTr}?`)KS&2$3NR@a+>+hqK*6r6Uu-H};ZG^| zfq_Vl%YE1*uGwtJ>H*Y(Q9E6kOfLJRlrDNv`N;jnag&f<4#UErM0ECf$8DASxMFF& zK=mZgu)xBz6lXJ~WZR7OYw;4&?v3Kk-QTs;v1r%XhgzSWVf|`Sre2XGdJb}l1!a~z zP92YjnfI7OnF@4~g*LF>G9IZ5c+tifpcm6#m)+BmnZ1kz+pM8iUhwag`_gqr(bnpy zl-noA2L@2+?*7`ZO{P7&UL~ahldjl`r3=HIdo~Hq#d+&Q;)LHZ4&5zuDNug@9-uk; z<2&m#0Um`s=B}_}9s&70Tv_~Va@WJ$n~s`7tVxi^s&_nPI0`QX=JnItlOu*Tn;T@> zXsVNAHd&K?*u~a@u8MWX17VaWuE0=6B93P2IQ{S$-WmT+Yp!9eA>@n~=s>?uDQ4*X zC(SxlKap@0R^z1p9C(VKM>nX8-|84nvIQJ-;9ei0qs{}X>?f%&E#%-)Bpv_p;s4R+ z;PMpG5*rvN&l;i{^~&wKnEhT!S!LQ>udPzta#Hc9)S8EUHK=%x+z@iq!O{)*XM}aI zBJE)vokFFXTeG<2Pq}5Na+kKnu?Ch|YoxdPb&Z{07nq!yzj0=xjzZj@3XvwLF0}Pa zn;x^HW504NNfLY~w!}5>`z=e{nzGB>t4ntE>R}r7*hJF3OoEx}&6LvZz4``m{AZxC zz6V+^73YbuY>6i9ulu)2`ozP(XBY5n$!kiAE_Vf4}Ih)tlOjgF3HW|DF+q-jI_0p%6Voc^e;g28* z;Sr4X{n(X7eEnACWRGNsHqQ_OfWhAHwnSQ87@PvPcpa!xr9`9+{QRn;bh^jgO8q@v zLekO@-cdc&eOKsvXs-eMCH8Y{*~3Iy!+CANy+(WXYS&6XB$&1+tB?!qcL@@) zS7XQ|5=o1fr8yM7r1AyAD~c@Mo`^i~hjx{N17%pDX?j@2bdBEbxY}YZxz!h#)q^1x zpc_RnoC3`V?L|G2R1QbR6pI{Am?yW?4Gy`G-xBYfebXvZ=(nTD7u?OEw>;vQICdPJBmi~;xhVV zisVvnE!bxI5|@IIlDRolo_^tc1{m)XTbIX^<{TQfsUA1Wv(KjJED^nj`r!JjEA%MaEGqPB z9YVt~ol3%e`PaqjZt&-)Fl^NeGmZ)nbL;92cOeLM2H*r-zA@d->H5T_8_;Jut0Q_G zBM2((-VHy2&eNkztIpHk&1H3M3@&wvvU9+$RO%fSEa_d5-qZ!<`-5?L9lQ1@AEpo* z3}Zz~R6&^i9KfRM8WGc6fTFD%PGdruE}`X$tP_*A)_7(uI5{k|LYc-WY*%GJ6JMmw zNBT%^E#IhekpA(i zcB$!EB}#>{^=G%rQ~2;gbObT9PQ{~aVx_W6?(j@)S$&Ja1s}aLT%A*mP}NiG5G93- z_DaRGP77PzLv0s32{UFm##C2LsU!w{vHdKTM1X)}W%OyZ&{3d^2Zu-zw?fT=+zi*q z^fu6CXQ!i?=ljsqSUzw>g#PMk>(^#ejrYp(C)7+@Z1=Mw$Rw!l8c9}+$Uz;9NUO(kCd#A1DX4Lbis0k; z?~pO(;@I6Ajp}PL;&`3+;OVkr3A^dQ(j?`by@A!qQam@_5(w6fG>PvhO`#P(y~2ue zW1BH_GqUY&>PggMhhi@8kAY;XWmj>y1M@c`0v+l~l0&~Kd8ZSg5#46wTLPo*Aom-5 z>qRXyWl}Yda=e@hJ%`x=?I42(B0lRiR~w>n6p8SHN~B6Y>W(MOxLpv>aB)E<1oEcw z%X;#DJpeDaD;CJRLX%u!t23F|cv0ZaE183LXxMq*uWn)cD_ zp!@i5zsmcxb!5uhp^@>U;K>$B|8U@3$65CmhuLlZ2(lF#hHq-<<+7ZN9m3-hFAPgA zKi;jMBa*59ficc#TRbH_l`2r>z(Bm_XEY}rAwyp~c8L>{A<0@Q)j*uXns^q5z~>KI z)43=nMhcU1ZaF;CaBo>hl6;@(2#9yXZ7_BwS4u>gN%SBS<;j{{+p}tbD8y_DFu1#0 zx)h&?`_`=ti_6L>VDH3>PPAc@?wg=Omdoip5j-2{$T;E9m)o2noyFW$5dXb{9CZ?c z);zf3U526r3Fl+{82!z)aHkZV6GM@%OKJB5mS~JcDjieFaVn}}M5rtPnHQVw0Stn- zEHs_gqfT8(0b-5ZCk1%1{QQaY3%b>wU z7lyE?lYGuPmB6jnMI6s$1uxN{Tf_n7H~nKu+h7=%60WK-C&kEIq_d4`wU(*~rJsW< zo^D$-(b0~uNVgC+$J3MUK)(>6*k?92mLgpod{Pd?{os+yHr&t+9ZgM*9;dCQBzE!V zk6e6)9U6Bq$^_`E1xd}d;5O8^6?@bK>QB&7l{vAy^P6FOEO^l7wK4K=lLA45gQ3$X z=$N{GR1{cxO)j;ZxKI*1kZIT9p>%FhoFbRK;M(m&bL?SaN zzkZS9xMf={o@gpG%wE857u@9dq>UKvbaM1SNtMA9EFOp7$BjJQVkIm$wU?-yOOs{i z1^(E(WwZZG{_#aIzfpGc@g5-AtK^?Q&vY#CtVpfLbW?g0{BEX4Vlk(`AO1{-D@31J zce}#=$?Gq+FZG-SD^z)-;wQg9`qEO}Dvo+S9*PUB*JcU)@S;UVIpN7rOqXmEIerWo zP_lk!@RQvyds&zF$Rt>N#_=!?5{XI`Dbo0<@>fIVgcU*9Y+ z)}K(Y&fdgve3ruT{WCNs$XtParmvV;rjr&R(V&_#?ob1LzO0RW3?8_kSw)bjom#0; zeNllfz(HlOJw012B}rgCUF5o|Xp#HLC~of%lg+!pr(g^n;wCX@Yk~SQOss!j9f(KL zDiI1h#k{po=Irl)8N*KU*6*n)A8&i9Wf#7;HUR^5*6+Bzh;I*1cICa|`&`e{pgrdc zs}ita0AXb$c6{tu&hxmT0faMG0GFc)unG8tssRJd%&?^62!_h_kn^HU_kBgp$bSew zqu)M3jTn;)tipv9Wt4Ll#1bmO2n?^)t^ZPxjveoOuK89$oy4(8Ujw{nd*Rs*<+xFi z{k*9v%sl?wS{aBSMMWdazhs0#gX9Has=pi?DhG&_0|cIyRG7c`OBiVG6W#JjYf7-n zIQU*Jc+SYnI8oG^Q8So9SP_-w;Y00$p5+LZ{l+81>v7|qa#Cn->312n=YQd$PaVz8 zL*s?ZU*t-RxoR~4I7e^c!8TA4g>w@R5F4JnEWJpy>|m5la2b#F4d*uoz!m=i1;`L` zB(f>1fAd~;*wf%GEbE8`EA>IO9o6TdgbIC%+en!}(C5PGYqS0{pa?PD)5?ds=j9{w za9^@WBXMZ|D&(yfc~)tnrDd#*;u;0?8=lh4%b-lFPR3ItwVJp};HMdEw#SXg>f-zU zEiaj5H=jzRSy(sWVd%hnLZE{SUj~$xk&TfheSch#23)YTcjrB+IVe0jJqsdz__n{- zC~7L`DG}-Dgrinzf7Jr)e&^tdQ}8v7F+~eF*<`~Vph=MIB|YxNEtLo1jXt#9#UG5` zQ$OSk`u!US+Z!=>dGL>%i#uV<5*F?pivBH@@1idFrzVAzttp5~>Y?D0LV;8Yv`wAa{hewVjlhhBM z_mJhU9yWz9Jexg@G~dq6EW5^nDXe(sU^5{}qbd0*yW2Xq6G37f8{{X&Z>G~dUGDFu zgmsDDZZ5ZmtiBw58CERFPrEG>*)*`_B75!MDsOoK`T1aJ4GZ1avI?Z3OX|Hg?P(xy zSPgO$alKZuXd=pHP6UZy0G>#BFm(np+dekv0l6gd=36FijlT8^kI5; zw?Z*FPsibF2d9T$_L@uX9iw*>y_w9HSh8c=Rm}f>%W+8OS=Hj_wsH-^actull3c@!z@R4NQ4qpytnwMaY z)>!;FUeY?h2N9tD(othc7Q=(dF zZAX&Y1ac1~0n(z}!9{J2kPPnru1?qteJPvA2m!@3Zh%+f1VQt~@leK^$&ZudOpS!+ zw#L0usf!?Df1tB?9=zPZ@q2sG!A#9 zKZL`2cs%|Jf}wG=_rJkwh|5Idb;&}z)JQuMVCZSH9kkG%zvQO01wBN)c4Q`*xnto3 zi7TscilQ>t_SLij{@Fepen*a(`upw#RJAx|JYYXvP1v8f)dTHv9pc3ZUwx!0tOH?c z^Hn=gfjUyo!;+3vZhxNE?LJgP`qYJ`J)umMXT@b z{nU(a^xFfofcxfHN-!Jn*{Dp5NZ&i9#9r{)s^lUFCzs5LQL9~HgxvmU#W|iNs0<3O z%Y2FEgvts4t({%lfX1uJ$w{JwfpV|HsO{ZDl2|Q$-Q?UJd`@SLBsMKGjFFrJ(s?t^ z2Llf`deAe@YaGJf)k2e&ryg*m8R|pcjct@rOXa=64#V9!sp=6tC#~QvYh&M~zmJ;% zr*A}V)Ka^3JE!1pcF5G}b&jdrt;bM^+J;G^#R08x@{|ZWy|547&L|k6)HLG|sN<~o z?y`%kbfRN_vc}pwS!Zr}*q6DG7;be0qmxn)eOcD%s3Wk`=@GM>U3ojhAW&WRppi0e zudTj{ufwO~H7izZJmLJD3uPHtjAJvo6H=)&SJ_2%qRRECN#HEU_RGa(Pefk*HIvOH zW7{=Tt(Q(LZ6&WX_Z9vpen}jqge|wCCaLYpiw@f_%9+-!l{kYi&gT@Cj#D*&rz1%e z@*b1W13bN8^j7IpAi$>`_0c!aVzLe*01DY-AcvwE;kW}=Z{3RJLR|O~^iOS(dNEnL zJJ?Dv^ab++s2v!4Oa_WFDLc4fMspglkh;+vzg)4;LS{%CR*>VwyP4>1Tly+!fA-k? z6$bg!*>wKtg!qGO6GQ=cAmM_RC&hKg$~(m2LdP{{*M+*OVf07P$OHp*4SSj9H;)1p z^b1_4p4@C;8G7cBCB6XC{i@vTB3#55iRBZiml^jc4sYnepCKUD+~k}TiuA;HWC6V3 zV{L5uUAU9CdoU+qsFszEwp;@d^!6XnX~KI|!o|=r?qhs`(-Y{GfO4^d6?8BC0xonf zKtZc1C@dNu$~+p#m%JW*J7alfz^$x`U~)1{c7svkIgQ3~RK2LZ5;2TAx=H<4AjC8{ z;)}8OfkZy7pSzVsdX|wzLe=SLg$W1+`Isf=o&}npxWdVR(i8Rr{uzE516a@28VhVr zVgZ3L&X(Q}J0R2{V(}bbNwCDD5K)<5h9CLM*~!xmGTl{Mq$@;~+|U*O#nc^oHnFOy z9Kz%AS*=iTBY_bSZAAY6wXCI?EaE>8^}WF@|}O@I#i69ljjWQPBJVk zQ_rt#J56_wGXiyItvAShJpLEMtW_)V5JZAuK#BAp6bV3K;IkS zK0AL(3ia99!vUPL#j>?<>mA~Q!mC@F-9I$9Z!96ZCSJO8FDz1SP3gF~m`1c#y!efq8QN}eHd+BHwtm%M5586jlU8&e!CmOC z^N_{YV$1`II$~cTxt*dV{-yp61nUuX5z?N8GNBuZZR}Uy_Y3_~@Y3db#~-&0TX644OuG^D3w_`?Yci{gTaPWST8`LdE)HK5OYv>a=6B%R zw|}>ngvSTE1rh`#1Rey0?LXTq;bCIy>TKm^CTV4BCSqdpx1pzC3^ca*S3fUBbKMzF z6X%OSdtt50)yJw*V_HE`hnBA)1yVN3Ruq3l@lY;%Bu+Q&hYLf_Z@fCUVQY-h4M3)- zE_G|moU)Ne0TMjhg?tscN7#ME6!Rb+y#Kd&-`!9gZ06o3I-VX1d4b1O=bpRG-tDK0 zSEa9y46s7QI%LmhbU3P`RO?w#FDM(}k8T`&>OCU3xD=s5N7}w$GntXF;?jdVfg5w9OR8VPxp5{uw zD+_;Gb}@7Vo_d3UV7PS65%_pBUeEwX_Hwfe2e6Qmyq$%0i8Ewn%F7i%=CNEV)Qg`r|&+$ zP6^Vl(MmgvFq`Zb715wYD>a#si;o+b4j^VuhuN>+sNOq6Qc~Y;Y=T&!Q4>(&^>Z6* zwliz!_16EDLTT;v$@W(s7s0s zi*%p>q#t)`S4j=Ox_IcjcllyT38C4hr&mlr6qX-c;qVa~k$MG;UqdnzKX0wo0Xe-_)b zrHu1&21O$y5828UIHI@N;}J@-9cpxob}zqO#!U%Q*ybZ?BH#~^fOT_|8&xAs_rX24 z^nqn{UWqR?MlY~klh)#Rz-*%&e~9agOg*fIN`P&v!@gcO25Mec23}PhzImkdwVT|@ zFR9dYYmf&HiUF4xO9@t#u=uTBS@k*97Z!&hu@|xQnQDkLd!*N`!0JN7{EUoH%OD85 z@aQ2(w-N)1_M{;FV)C#(a4p!ofIA3XG(XZ2E#%j_(=`IWlJAHWkYM2&(+yY|^2TB0 z>wfC-+I}`)LFOJ%KeBb1?eNxGKeq?AI_eBE!M~$wYR~bB)J3=WvVlT8ZlF2EzIFZt zkaeyj#vmBTGkIL9mM3cEz@Yf>j=82+KgvJ-u_{bBOxE5zoRNQW3+Ahx+eMGem|8xo zL3ORKxY_R{k=f~M5oi-Z>5fgqjEtzC&xJEDQ@`<)*Gh3UsftBJno-y5Je^!D?Im{j za*I>RQ=IvU@5WKsIr?kC$DT+2bgR>8rOf3mtXeMVB~sm%X7W5`s=Tp>FR544tuQ>9qLt|aUSv^io&z93luW$_OYE^sf8DB?gx z4&k;dHMWph>Z{iuhhFJr+PCZ#SiZ9e5xM$A#0yPtVC>yk&_b9I676n|oAH?VeTe*1 z@tDK}QM-%J^3Ns6=_vh*I8hE?+=6n9nUU`}EX|;Mkr?6@NXy8&B0i6h?7%D=%M*Er zivG61Wk7e=v;<%t*G+HKBqz{;0Biv7F+WxGirONRxJij zon5~(a`UR%uUzfEma99QGbIxD(d}~oa|exU5Y27#4k@N|=hE%Y?Y3H%rcT zHmNO#ZJ7nPHRG#y-(-FSzaZ2S{`itkdYY^ZUvyw<7yMBkNG+>$Rfm{iN!gz7eASN9-B3g%LIEyRev|3)kSl;JL zX7MaUL_@~4ot3$woD0UA49)wUeu7#lj77M4ar8+myvO$B5LZS$!-ZXw3w;l#0anYz zDc_RQ0Ome}_i+o~H=CkzEa&r~M$1GC!-~WBiHiDq9Sdg{m|G?o7g`R%f(Zvby5q4; z=cvn`M>RFO%i_S@h3^#3wImmWI4}2x4skPNL9Am{c!WxR_spQX3+;fo!y(&~Palyjt~Xo0uy6d%sX&I`e>zv6CRSm)rc^w!;Y6iVBb3x@Y=`hl9jft zXm5vilB4IhImY5b->x{!MIdCermpyLbsalx8;hIUia%*+WEo4<2yZ6`OyG1Wp%1s$ zh<|KrHMv~XJ9dC8&EXJ`t3ETz>a|zLMx|MyJE54RU(@?K&p2d#x?eJC*WKO9^d17# zdTTKx-Os3k%^=58Sz|J28aCJ}X2-?YV3T7ee?*FoDLOC214J4|^*EX`?cy%+7Kb3(@0@!Q?p zk>>6dWjF~y(eyRPqjXqDOT`4^Qv-%G#Zb2G?&LS-EmO|ixxt79JZlMgd^~j)7XYQ; z62rGGXA=gLfgy{M-%1gR87hbhxq-fL)GSfEAm{yLQP!~m-{4i_jG*JsvUdqAkoc#q6Yd&>=;4udAh#?xa2L z7mFvCjz(hN7eV&cyFb%(U*30H@bQ8-b7mkm!=wh2|;+_4vo=tyHPQ0hL=NR`jbsSiBWtG ztMPPBgHj(JTK#0VcP36Z`?P|AN~ybm=jNbU=^3dK=|rLE+40>w+MWQW%4gJ`>K!^- zx4kM*XZLd(E4WsolMCRsdvTGC=37FofIyCZCj{v3{wqy4OXX-dZl@g`Dv>p2`l|H^ zS_@(8)7gA62{Qfft>vx71stILMuyV4uKb7BbCstG@|e*KWl{P1$=1xg(7E8MRRCWQ1g)>|QPAZot~|FYz_J0T+r zTWTB3AatKyUsTXR7{Uu) z$1J5SSqoJWt(@@L5a)#Q6bj$KvuC->J-q1!nYS6K5&e7vNdtj- zj9;qwbODLgIcObqNRGs1l{8>&7W?BbDd!87=@YD75B2ep?IY|gE~t)$`?XJ45MG@2 zz|H}f?qtEb_p^Xs$4{?nA=Qko3Lc~WrAS`M%9N60FKqL7XI+v_5H-UDiCbRm`fEmv z$pMVH*#@wQqml~MZe+)e4Ts3Gl^!Z0W3y$;|9hI?9(iw29b7en0>Kt2pjFXk@!@-g zTb4}Kw!@u|V!wzk0|qM*zj$*-*}e*ZXs#Y<6E_!BR}3^YtjI_byo{F+w9H9?f%mnBh(uE~!Um7)tgp2Ye;XYdVD95qt1I-fc@X zXHM)BfJ?^g(s3K|{N8B^hamrWAW|zis$`6|iA>M-`0f+vq(FLWgC&KnBDsM)_ez1# zPCTfN8{s^K`_bum2i5SWOn)B7JB0tzH5blC?|x;N{|@ch(8Uy-O{B2)OsfB$q0@FR z27m3YkcVi$KL;;4I*S;Z#6VfZcZFn!D2Npv5pio)sz-`_H*#}ROd7*y4i(y(YlH<4 zh4MmqBe^QV_$)VvzWgMXFy`M(vzyR2u!xx&%&{^*AcVLrGa8J9ycbynjKR~G6zC0e zlEU>zt7yQtMhz>XMnz>ewXS#{Bulz$6HETn?qD5v3td>`qGD;Y8&RmkvN=24=^6Q@DYY zxMt}uh2cSToMkkIWo1_Lp^FOn$+47JXJ*#q=JaeiIBUHEw#IiXz8cStEsw{UYCA5v_%cF@#m^Y!=+qttuH4u}r6gMvO4EAvjBURtLf& z6k!C|OU@hv_!*qear3KJ?VzVXDKqvKRtugefa7^^MSWl0fXXZR$Xb!b6`eY4A1#pk zAVoZvb_4dZ{f~M8fk3o?{xno^znH1t;;E6K#9?erW~7cs%EV|h^K>@&3Im}c7nm%Y zbLozFrwM&tSNp|46)OhP%MJ(5PydzR>8)X%i3!^L%3HCoCF#Y0#9vPI5l&MK*_ z6G8Y>$`~c)VvQle_4L_AewDGh@!bKkJeEs_NTz(yilnM!t}7jz>fmJb89jQo6~)%% z@GNIJ@AShd&K%UdQ5vR#yT<-goR+D@Tg;PuvcZ*2AzSWN&wW$Xc+~vW)pww~O|6hL zBxX?hOyA~S;3rAEfI&jmMT4f!-eVm%n^KF_QT=>!A<5tgXgi~VNBXqsFI(iI$Tu3x0L{<_-%|HMG4Cn?Xs zq~fvBhu;SDOCD7K5(l&i7Py-;Czx5byV*3y%#-Of9rtz?M_owXc2}$OIY~)EZ&2?r zLQ(onz~I7U!w?B%LtfDz)*X=CscqH!UE=mO?d&oYvtj|(u)^yomS;Cd>Men|#2yuD zg&tf(*iSHyo;^A03p&_j*QXay9d}qZ0CgU@rnFNDIT5xLhC5_tlugv()+w%`7;ICf z>;<#L4m@{1}Og76*e zHWFm~;n@B1GqO8s%=qu)+^MR|jp(ULUOi~v;wE8SB6^mK@adSb=o+A_>Itjn13AF& zDZe+wUF9G!JFv|dpj1#d+}BO~s*QTe3381TxA%Q>P*J#z%( z5*8N^QWxgF73^cTKkkvgvIzf*cLEyyKw)Wf{#$n{uS#(rAA~>TS#!asqQ2m_izXe3 z7$Oh=rR;sdmVx3G)s}eImsb<@r2~5?vcw*Q4LU~FFh!y4r*>~S7slAE6)W3Up2OHr z2R)+O<0kKo<3+5vB}v!lB*`%}gFldc+79iahqEx#&Im@NCQU$@PyCZbcTt?K{;o@4 z312O9GB)?X&wAB}*-NEU zn@6`)G`FhT8O^=Cz3y+XtbwO{5+{4-&?z!esFts-C zypwgI^4#tZ74KC+_IW|E@kMI=1pSJkvg$9G3Va(!reMnJ$kcMiZ=30dTJ%(Ws>eUf z;|l--TFDqL!PZbLc_O(XP0QornpP;!)hdT#Ts7tZ9fcQeH&rhP_1L|Z_ha#JOroe^qcsLi`+AoBWHPM7}gD z+mHuPXd14M?nkp|nu9G8hPk;3=JXE-a204Fg!BK|$MX`k-qPeD$2OOqvF;C(l8wm13?>i(pz7kRyYm zM$IEzf`$}B%ezr!$(UO#uWExn%nTCTIZzq&8@i8sP#6r8 z*QMUzZV(LEWZb)wbmf|Li;UpiP;PlTQ(X4zreD`|`RG!7_wc6J^MFD!A=#K*ze>Jg z?9v?p(M=fg_VB0+c?!M$L>5FIfD(KD5ku*djwCp+5GVIs9^=}kM2RFsxx0_5DE%BF zykxwjWvs=rbi4xKIt!z$&v(`msFrl4n>a%NO_4`iSyb!UiAE&mDa+apc zPe)#!ToRW~rqi2e1bdO1RLN5*uUM@{S`KLJhhY-@TvC&5D(c?a(2$mW-&N%h5IfEM zdFI6`6KJiJQIHvFiG-34^BtO3%*$(-Ht_JU*(KddiUYoM{coadlG&LVvke&*p>Cac z^BPy2Zteiq1@ulw0e)e*ot7@A$RJui0$l^{lsCt%R;$){>zuRv9#w@;m=#d%%TJmm zC#%eFOoy$V)|3*d<OC1iP+4R7D z8FE$E8l2Y?(o-i6wG=BKBh0-I?i3WF%hqdD7VCd;vpk|LFP!Et8$@voH>l>U8BY`Q zC*G;&y6|!p=7`G$*+hxCv!@^#+QD3m>^azyZoLS^;o_|plQaj-wx^ zRV&$HcY~p)2|Zqp0SYU?W3zV87s6JP-@D~$t0 zvd;-YL~JWc*8mtHz_s(cXus#XYJc5zdC=&!4MeZ;N3TQ>^I|Pd=HPjVP*j^45rs(n zzB{U4-44=oQ4rNN6@>qYVMH4|GmMIz#z@3UW-1_y#eNa+Q%(41oJ5i(DzvMO^%|?L z^r_+MZtw0DZ0=BT-@?hUtA)Ijk~Kh-N8?~X5%KnRH7cb!?Yrd8gtiEo!v{sGrQk{X zvV>h{8-DqTyuAxIE(hb}jMVtga$;FIrrKm>ye5t%M;p!jcH1(Bbux>4D#MVhgZGd> z=c=nVb%^9T?iDgM&9G(mV5xShc-lBLi*6RShenDqB%`-2;I*;IHg6>#ovKQ$M}dDb z<$USN%LMqa5_5DR7g7@(oAoQ%!~<1KSQr$rmS{UFQJs5&qBhgTEM_Y7|0Wv?fbP`z z)`8~=v;B)+>Jh`V*|$dTxKe`HTBkho^-!!K#@i{9FLn-XqX&fQcGsEAXp)BV7(`Lk zC{4&+Pe-0&<)C0kAa(MTnb|L;ZB5i|b#L1o;J)+?SV8T*U9$Vxhy}dm3%!A}SK9l_6(#5(e*>8|;4gNKk7o_%m_ zEaS=Z(ewk}hBJ>v`jtR=$pm_Wq3d&DU+6`BACU4%qdhH1o^m8hT2&j<4Z8!v=rMCk z-I*?48{2H*&+r<{2?wp$kh@L@=rj8c`EaS~J>W?)trc?zP&4bsNagS4yafuDoXpi5`!{BVqJ1$ZC3`pf$`LIZ(`0&Ik+!_Xa=NJW`R2 zd#Ntgwz`JVwC4A61$FZ&kP)-{T|rGO59`h#1enAa`cWxRR8bKVvvN6jBzAYePrc&5 z+*zr3en|LYB2>qJp479rEALk5d*X-dfKn6|kuNm;2-U2+P3_rma!nWjZQ-y*q3JS? zBE}zE-!1ZBR~G%v!$l#dZ*$UV4$7q}xct}=on+Ba8{b>Y9h*f-GW0D0o#vJ0%ALg( ztG2+AjWlG#d;myA(i&dh8Gp?y9HD@`CTaDAy?c&0unZ%*LbLIg4;m{Kc?)ws3^>M+ zt5>R)%KIJV*MRUg{0$#nW=Lj{#8?dD$yhjBOrAeR#4$H_Dc(eyA4dNjZEz1Xk+Bqt zB&pPl+?R{w8GPv%VI`x`IFOj320F1=cV4aq0(*()Tx!VVxCjua;)t}gTr=b?zY+U! zkb}xjXZ?hMJN{Hjw?w&?gz8Ow`htX z@}WG*_4<%ff8(!S6bf3)p+8h2!Rory>@aob$gY#fYJ=LiW0`+~l7GI%EX_=8 z{(;0&lJ%9)M9{;wty=XvHbIx|-$g4HFij`J$-z~`mW)*IK^MWVN+*>uTNqaDmi!M8 zurj6DGd)g1g(f`A-K^v)3KSOEoZXImXT06apJum-dO_%oR)z6Bam-QC&CNWh7kLOE zcxLdVjYLNO2V?IXWa-ys30Jbxw(Xm?U1{4kDs9`gZQHh8X{*w9=H&Zz&-6RL?uq#R zxN+k~JaL|gdsdvY_u6}}MHC?a@ElFeipA1Lud#M~)pp2SnG#K{a@tSpvXM;A8gz9> zRVDV5T1%%!LsNRDOw~LIuiAiKcj<%7WpgjP7G6mMU1#pFo6a-1>0I5ZdhxnkMX&#L z=Vm}?SDlb_LArobqpnU!WLQE*yVGWgs^4RRy4rrJwoUUWoA~ZJUx$mK>J6}7{CyC4 zv=8W)kKl7TmAnM%m;anEDPv5tzT{A{ON9#FPYF6c=QIc*OrPp96tiY&^Qs+#A1H>Y z<{XtWt2eDwuqM zQ_BI#UIP;2-olOL4LsZ`vTPv-eILtuB7oWosoSefWdM}BcP>iH^HmimR`G`|+9waCO z&M375o@;_My(qYvPNz;N8FBZaoaw3$b#x`yTBJLc8iIP z--la{bzK>YPP|@Mke!{Km{vT8Z4|#An*f=EmL34?!GJfHaDS#41j~8c5KGKmj!GTh&QIH+DjEI*BdbSS2~6VTt}t zhAwNQNT6%c{G`If3?|~Fp7iwee(LaUS)X9@I29cIb61} z$@YBq4hSplr&liE@ye!y&7+7n$fb+8nS~co#^n@oCjCwuKD61x$5|0ShDxhQES5MP z(gH|FO-s6#$++AxnkQR!3YMgKcF)!&aqr^a3^{gAVT`(tY9@tqgY7@ z>>ul3LYy`R({OY7*^Mf}UgJl(N7yyo$ag;RIpYHa_^HKx?DD`%Vf1D0s^ zjk#OCM5oSzuEz(7X`5u~C-Y~n4B}_3*`5B&8tEdND@&h;H{R`o%IFpIJ4~Kw!kUjehGT8W!CD7?d8sg_$KKp%@*dW)#fI1#R<}kvzBVpaog_2&W%c_jJfP` z6)wE+$3+Hdn^4G}(ymPyasc1<*a7s2yL%=3LgtZLXGuA^jdM^{`KDb%%}lr|ONDsl zy~~jEuK|XJ2y<`R{^F)Gx7DJVMvpT>gF<4O%$cbsJqK1;v@GKXm*9l3*~8^_xj*Gs z=Z#2VQ6`H@^~#5Pv##@CddHfm;lbxiQnqy7AYEH(35pTg^;u&J2xs-F#jGLuDw2%z z`a>=0sVMM+oKx4%OnC9zWdbpq*#5^yM;og*EQKpv`^n~-mO_vj=EgFxYnga(7jO?G z`^C87B4-jfB_RgN2FP|IrjOi;W9AM1qS}9W@&1a9Us>PKFQ9~YE!I~wTbl!m3$Th? z)~GjFxmhyyGxN}t*G#1^KGVXm#o(K0xJyverPe}mS=QgJ$#D}emQDw+dHyPu^&Uv> z4O=3gK*HLFZPBY|!VGq60Of6QrAdj`nj1h!$?&a;Hgaj{oo{l0P3TzpJK_q_eW8Ng zP6QF}1{V;xlolCs?pGegPoCSxx@bshb#3ng4Fkp4!7B0=&+1%187izf@}tvsjZ6{m z4;K>sR5rm97HJrJ`w}Y`-MZN$Wv2N%X4KW(N$v2@R1RkRJH2q1Ozs0H`@ zd5)X-{!{<+4Nyd=hQ8Wm3CCd}ujm*a?L79ztfT7@&(?B|!pU5&%9Rl!`i;suAg0+A zxb&UYpo-z}u6CLIndtH~C|yz&!OV_I*L;H#C7ie_5uB1fNRyH*<^d=ww=gxvE%P$p zRHKI{^{nQlB9nLhp9yj-so1is{4^`{Xd>Jl&;dX;J)#- z=fmE5GiV?-&3kcjM1+XG7&tSq;q9Oi4NUuRrIpoyp*Fn&nVNFdUuGQ_g)g>VzXGdneB7`;!aTUE$t* z5iH+8XPxrYl)vFo~+vmcU-2) zq!6R(T0SsoDnB>Mmvr^k*{34_BAK+I=DAGu){p)(ndZqOFT%%^_y;X(w3q-L``N<6 zw9=M zoQ8Lyp>L_j$T20UUUCzYn2-xdN}{e@$8-3vLDN?GbfJ>7*qky{n!wC#1NcYQr~d51 zy;H!am=EI#*S&TCuP{FA3CO)b0AAiN*tLnDbvKwxtMw-l;G2T@EGH)YU?-B`+Y=!$ zypvDn@5V1Tr~y~U0s$ee2+CL3xm_BmxD3w}d_Pd@S%ft#v~_j;6sC6cy%E|dJy@wj z`+(YSh2CrXMxI;yVy*=O@DE2~i5$>nuzZ$wYHs$y`TAtB-ck4fQ!B8a;M=CxY^Nf{ z+UQhn0jopOzvbl(uZZ1R-(IFaprC$9hYK~b=57@ zAJ8*pH%|Tjotzu5(oxZyCQ{5MAw+6L4)NI!9H&XM$Eui-DIoDa@GpNI=I4}m>Hr^r zZjT?xDOea}7cq+TP#wK1p3}sbMK{BV%(h`?R#zNGIP+7u@dV5#zyMau+w}VC1uQ@p zrFUjrJAx6+9%pMhv(IOT52}Dq{B9njh_R`>&j&5Sbub&r*hf4es)_^FTYdDX$8NRk zMi=%I`)hN@N9>X&Gu2RmjKVsUbU>TRUM`gwd?CrL*0zxu-g#uNNnnicYw=kZ{7Vz3 zULaFQ)H=7%Lm5|Z#k?<{ux{o4T{v-e zTLj?F(_qp{FXUzOfJxEyKO15Nr!LQYHF&^jMMBs z`P-}WCyUYIv>K`~)oP$Z85zZr4gw>%aug1V1A)1H(r!8l&5J?ia1x_}Wh)FXTxZUE zs=kI}Ix2cK%Bi_Hc4?mF^m`sr6m8M(n?E+k7Tm^Gn}Kf= zfnqoyVU^*yLypz?s+-XV5(*oOBwn-uhwco5b(@B(hD|vtT8y7#W{>RomA_KchB&Cd zcFNAD9mmqR<341sq+j+2Ra}N5-3wx5IZqg6Wmi6CNO#pLvYPGNER}Q8+PjvIJ42|n zc5r@T*p)R^U=d{cT2AszQcC6SkWiE|hdK)m{7ul^mU+ED1R8G#)#X}A9JSP_ubF5p z8Xxcl;jlGjPwow^p+-f_-a~S;$lztguPE6SceeUCfmRo=Qg zKHTY*O_ z;pXl@z&7hniVYVbGgp+Nj#XP^Aln2T!D*{(Td8h{8Dc?C)KFfjPybiC`Va?Rf)X>y z;5?B{bAhPtbmOMUsAy2Y0RNDQ3K`v`gq)#ns_C&ec-)6cq)d^{5938T`Sr@|7nLl; zcyewuiSUh7Z}q8iIJ@$)L3)m)(D|MbJm_h&tj^;iNk%7K-YR}+J|S?KR|29K?z-$c z<+C4uA43yfSWBv*%z=-0lI{ev`C6JxJ};A5N;lmoR(g{4cjCEn33 z-ef#x^uc%cM-f^_+*dzE?U;5EtEe;&8EOK^K}xITa?GH`tz2F9N$O5;)`Uof4~l+t z#n_M(KkcVP*yMYlk_~5h89o zlf#^qjYG8Wovx+f%x7M7_>@r7xaXa2uXb?_*=QOEe_>ErS(v5-i)mrT3&^`Oqr4c9 zDjP_6T&NQMD`{l#K&sHTm@;}ed_sQ88X3y`ON<=$<8Qq{dOPA&WAc2>EQ+U8%>yWR zK%(whl8tB;{C)yRw|@Gn4%RhT=bbpgMZ6erACc>l5^p)9tR`(2W-D*?Ph6;2=Fr|G- zdF^R&aCqyxqWy#P7#G8>+aUG`pP*ow93N=A?pA=aW0^^+?~#zRWcf_zlKL8q8-80n zqGUm=S8+%4_LA7qrV4Eq{FHm9#9X15%ld`@UKyR7uc1X*>Ebr0+2yCye6b?i=r{MPoqnTnYnq z^?HWgl+G&@OcVx4$(y;{m^TkB5Tnhx2O%yPI=r*4H2f_6Gfyasq&PN^W{#)_Gu7e= zVHBQ8R5W6j;N6P3O(jsRU;hkmLG(Xs_8=F&xh@`*|l{~0OjUVlgm z7opltSHg7Mb%mYamGs*v1-#iW^QMT**f+Nq*AzIvFT~Ur3KTD26OhIw1WQsL(6nGg znHUo-4e15cXBIiyqN};5ydNYJ6zznECVVR44%(P0oW!yQ!YH)FPY?^k{IrtrLo7Zo`?sg%%oMP9E^+H@JLXicr zi?eoI?LODRPcMLl90MH32rf8btf69)ZE~&4d%(&D{C45egC6bF-XQ;6QKkbmqW>_H z{86XDZvjiN2wr&ZPfi;^SM6W+IP0);50m>qBhzx+docpBkkiY@2bSvtPVj~E`CfEu zhQG5G>~J@dni5M5Jmv7GD&@%UR`k3ru-W$$onI259jM&nZ)*d3QFF?Mu?{`+nVzkx z=R*_VH=;yeU?9TzQ3dP)q;P)4sAo&k;{*Eky1+Z!10J<(cJC3zY9>bP=znA=<-0RR zMnt#<9^X7BQ0wKVBV{}oaV=?JA=>R0$az^XE%4WZcA^Em>`m_obQyKbmf-GA;!S-z zK5+y5{xbkdA?2NgZ0MQYF-cfOwV0?3Tzh8tcBE{u%Uy?Ky4^tn^>X}p>4&S(L7amF zpWEio8VBNeZ=l!%RY>oVGOtZh7<>v3?`NcHlYDPUBRzgg z0OXEivCkw<>F(>1x@Zk=IbSOn+frQ^+jI*&qdtf4bbydk-jgVmLAd?5ImK+Sigh?X zgaGUlbf^b-MH2@QbqCawa$H1Vb+uhu{zUG9268pa{5>O&Vq8__Xk5LXDaR1z$g;s~;+Ae82wq#l;wo08tX(9uUX6NJWq1vZLh3QbP$# zL`udY|Qp*4ER`_;$%)2 zmcJLj|FD`(;ts0bD{}Ghq6UAVpEm#>j`S$wHi0-D_|)bEZ}#6) zIiqH7Co;TB`<6KrZi1SF9=lO+>-_3=Hm%Rr7|Zu-EzWLSF{9d(H1v*|UZDWiiqX3} zmx~oQ6%9~$=KjPV_ejzz7aPSvTo+3@-a(OCCoF_u#2dHY&I?`nk zQ@t8#epxAv@t=RUM09u?qnPr6=Y5Pj;^4=7GJ`2)Oq~H)2V)M1sC^S;w?hOB|0zXT zQdf8$)jslO>Q}(4RQ$DPUF#QUJm-k9ysZFEGi9xN*_KqCs9Ng(&<;XONBDe1Joku? z*W!lx(i&gvfXZ4U(AE@)c0FI2UqrFLOO$&Yic|`L;Vyy-kcm49hJ^Mj^H9uY8Fdm2 z?=U1U_5GE_JT;Tx$2#I3rAAs(q@oebIK=19a$N?HNQ4jw0ljtyGJ#D}z3^^Y=hf^Bb--297h6LQxi0-`TB|QY2QPg92TAq$cEQdWE ze)ltSTVMYe0K4wte6;^tE+^>|a>Hit_3QDlFo!3Jd`GQYTwlR#{<^MzG zK!vW&))~RTKq4u29bc<+VOcg7fdorq-kwHaaCQe6tLB{|gW1_W_KtgOD0^$^|`V4C# z*D_S9Dt_DIxpjk3my5cBFdiYaq||#0&0&%_LEN}BOxkb3v*d$4L|S|z z!cZZmfe~_Y`46v=zul=aixZTQCOzb(jx>8&a%S%!(;x{M2!*$od2!Pwfs>RZ-a%GOZdO88rS)ZW~{$656GgW)$Q=@!x;&Nn~!K)lr4gF*%qVO=hlodHA@2)keS2 zC}7O=_64#g&=zY?(zhzFO3)f5=+`dpuyM!Q)zS&otpYB@hhn$lm*iK2DRt+#1n|L%zjM}nB*$uAY^2JIw zV_P)*HCVq%F))^)iaZD#R9n^{sAxBZ?Yvi1SVc*`;8|F2X%bz^+s=yS&AXjysDny)YaU5RMotF-tt~FndTK ziRve_5b!``^ZRLG_ks}y_ye0PKyKQSsQCJuK5()b2ThnKPFU?An4;dK>)T^4J+XjD zEUsW~H?Q&l%K4<1f5^?|?lyCQe(O3?!~OU{_Wxs#|Ff8?a_WPQUKvP7?>1()Cy6oLeA zjEF^d#$6Wb${opCc^%%DjOjll%N2=GeS6D-w=Ap$Ux2+0v#s#Z&s6K*)_h{KFfgKjzO17@p1nKcC4NIgt+3t}&}F z@cV; zZ1r#~?R@ZdSwbFNV(fFl2lWI(Zf#nxa<6f!nBZD>*K)nI&Fun@ngq@Ge!N$O< zySt*mY&0moUXNPe~Fg=%gIu)tJ;asscQ!-AujR@VJBRoNZNk;z4hs4T>Ud!y=1NwGs-k zlTNeBOe}=)Epw=}+dfX;kZ32h$t&7q%Xqdt-&tlYEWc>>c3(hVylsG{Ybh_M8>Cz0ZT_6B|3!_(RwEJus9{;u-mq zW|!`{BCtnao4;kCT8cr@yeV~#rf76=%QQs(J{>Mj?>aISwp3{^BjBO zLV>XSRK+o=oVDBnbv?Y@iK)MiFSl{5HLN@k%SQZ}yhPiu_2jrnI?Kk?HtCv>wN$OM zSe#}2@He9bDZ27hX_fZey=64#SNU#1~=icK`D>a;V-&Km>V6ZdVNj7d2 z-NmAoOQm_aIZ2lXpJhlUeJ95eZt~4_S zIfrDs)S$4UjyxKSaTi#9KGs2P zfSD>(y~r+bU4*#|r`q+be_dopJzKK5JNJ#rR978ikHyJKD>SD@^Bk$~D0*U38Y*IpYcH>aaMdZq|YzQ-Ixd(_KZK!+VL@MWGl zG!k=<%Y-KeqK%``uhx}0#X^@wS+mX@6Ul@90#nmYaKh}?uw>U;GS4fn3|X%AcV@iY z8v+ePk)HxSQ7ZYDtlYj#zJ?5uJ8CeCg3efmc#|a%2=u>+vrGGRg$S@^mk~0f;mIu! zWMA13H1<@hSOVE*o0S5D8y=}RiL#jQpUq42D}vW$z*)VB*FB%C?wl%(3>ANaY)bO@ zW$VFutemwy5Q*&*9HJ603;mJJkB$qp6yxNOY0o_4*y?2`qbN{m&*l{)YMG_QHXXa2 z+hTmlA;=mYwg{Bfusl zyF&}ib2J;#q5tN^e)D62fWW*Lv;Rnb3GO-JVtYG0CgR4jGujFo$Waw zSNLhc{>P~>{KVZE1Vl1!z)|HFuN@J7{`xIp_)6>*5Z27BHg6QIgqLqDJTmKDM+ON* zK0Fh=EG`q13l z+m--9UH0{ZGQ%j=OLO8G2WM*tgfY}bV~>3Grcrpehjj z6Xe<$gNJyD8td3EhkHjpKk}7?k55Tu7?#;5`Qcm~ki;BeOlNr+#PK{kjV>qfE?1No zMA07}b>}Dv!uaS8Hym0TgzxBxh$*RX+Fab6Gm02!mr6u}f$_G4C|^GSXJMniy^b`G z74OC=83m0G7L_dS99qv3a0BU({t$zHQsB-RI_jn1^uK9ka_%aQuE2+~J2o!7`735Z zb?+sTe}Gd??VEkz|KAPMfj(1b{om89p5GIJ^#Aics_6DD%WnNGWAW`I<7jT|Af|8g zZA0^)`p8i#oBvX2|I&`HC8Pn&0>jRuMF4i0s=}2NYLmgkZb=0w9tvpnGiU-gTUQhJ zR6o4W6ZWONuBZAiN77#7;TR1^RKE(>>OL>YU`Yy_;5oj<*}ac99DI(qGCtn6`949f ziMpY4k>$aVfffm{dNH=-=rMg|u?&GIToq-u;@1-W&B2(UOhC-O2N5_px&cF-C^tWp zXvChm9@GXEcxd;+Q6}u;TKy}$JF$B`Ty?|Y3tP$N@Rtoy(*05Wj-Ks32|2y2ZM>bM zi8v8E1os!yorR!FSeP)QxtjIKh=F1ElfR8U7StE#Ika;h{q?b?Q+>%78z^>gTU5+> zxQ$a^rECmETF@Jl8fg>MApu>btHGJ*Q99(tMqsZcG+dZ6Yikx7@V09jWCiQH&nnAv zY)4iR$Ro223F+c3Q%KPyP9^iyzZsP%R%-i^MKxmXQHnW6#6n7%VD{gG$E;7*g86G< zu$h=RN_L2(YHO3@`B<^L(q@^W_0#U%mLC9Q^XEo3LTp*~(I%?P_klu-c~WJxY1zTI z^PqntLIEmdtK~E-v8yc&%U+jVxW5VuA{VMA4Ru1sk#*Srj0Pk#tZuXxkS=5H9?8eb z)t38?JNdP@#xb*yn=<*_pK9^lx%;&yH6XkD6-JXgdddZty8@Mfr9UpGE!I<37ZHUe z_Rd+LKsNH^O)+NW8Ni-V%`@J_QGKA9ZCAMSnsN>Ych9VW zCE7R_1FVy}r@MlkbxZ*TRIGXu`ema##OkqCM9{wkWQJg^%3H${!vUT&vv2250jAWN zw=h)C!b2s`QbWhBMSIYmWqZ_~ReRW;)U#@C&ThctSd_V!=HA=kdGO-Hl57an|M1XC?~3f0{7pyjWY}0mChU z2Fj2(B*r(UpCKm-#(2(ZJD#Y|Or*Vc5VyLpJ8gO1;fCm@EM~{DqpJS5FaZ5%|ALw) zyumBl!i@T57I4ITCFmdbxhaOYud}i!0YkdiNRaQ%5$T5>*HRBhyB~<%-5nj*b8=i= z(8g(LA50%0Zi_eQe}Xypk|bt5e6X{aI^jU2*c?!p*$bGk=?t z+17R){lx~Z{!B34Zip~|A;8l@%*Gc}kT|kC0*Ny$&fI3@%M! zqk_zvN}7bM`x@jqFOtaxI?*^Im5ix@=`QEv;__i;Tek-&7kGm6yP17QANVL>*d0B=4>i^;HKb$k8?DYFMr38IX4azK zBbwjF%$>PqXhJh=*7{zH5=+gi$!nc%SqFZlwRm zmpctOjZh3bwt!Oc>qVJhWQf>`HTwMH2ibK^eE*j!&Z`-bs8=A`Yvnb^?p;5+U=Fb8 z@h>j_3hhazd$y^Z-bt%3%E3vica%nYnLxW+4+?w{%|M_=w^04U{a6^22>M_?{@mXP zS|Qjcn4&F%WN7Z?u&I3fU(UQVw4msFehxR*80dSb=a&UG4zDQp&?r2UGPy@G?0FbY zVUQ?uU9-c;f9z06$O5FO1TOn|P{pLcDGP?rfdt`&uw|(Pm@$n+A?)8 zP$nG(VG&aRU*(_5z#{+yVnntu`6tEq>%9~n^*ao}`F6ph_@6_8|AfAXtFfWee_14` zKKURYV}4}=UJmxv7{RSz5QlwZtzbYQs0;t3?kx*7S%nf-aY&lJ@h?-BAn%~0&&@j) zQd_6TUOLXErJ`A3vE?DJIbLE;s~s%eVt(%fMzUq^UfZV9c?YuhO&6pwKt>j(=2CkgTNEq7&c zfeGN+%5DS@b9HO>zsoRXv@}(EiA|t5LPi}*R3?(-=iASADny<{D0WiQG>*-BSROk4vI6%$R>q64J&v-T+(D<_(b!LD z9GL;DV;;N3!pZYg23mcg81tx>7)=e%f|i{6Mx0GczVpc}{}Mg(W_^=Wh0Rp+xXgX` z@hw|5=Je&nz^Xa>>vclstYt;8c2PY)87Ap;z&S&`yRN>yQVV#K{4&diVR7Rm;S{6m z6<+;jwbm`==`JuC6--u6W7A@o4&ZpJV%5+H)}toy0afF*!)AaG5=pz_i9}@OG%?$O z2cec6#@=%xE3K8;^ps<2{t4SnqH+#607gAHP-G4^+PBiC1s>MXf&bQ|Pa;WBIiErV z?3VFpR9JFl9(W$7p3#xe(Bd?Z93Uu~jHJFo7U3K_x4Ej-=N#=a@f;kPV$>;hiN9i9 z<6elJl?bLI$o=|d6jlihA4~bG;Fm2eEnlGxZL`#H%Cdes>uJfMJ4>@1SGGeQ81DwxGxy7L5 zm05Ik*WpSgZvHh@Wpv|2i|Y#FG?Y$hbRM5ZF0Z7FB3cY0+ei#km9mDSPI}^!<<`vr zuv$SPg2vU{wa)6&QMY)h1hbbxvR2cc_6WcWR`SH& z&KuUQcgu}!iW2Wqvp~|&&LSec9>t(UR_|f$;f-fC&tSO-^-eE0B~Frttnf+XN(#T) z^PsuFV#(pE#6ztaI8(;ywN%CtZh?w&;_)w_s@{JiA-SMjf&pQk+Bw<}f@Q8-xCQMwfaf zMgHsAPU=>>Kw~uDFS(IVRN{$ak(SV(hrO!UqhJ?l{lNnA1>U24!=>|q_p404Xd>M# z7?lh^C&-IfeIr`Dri9If+bc%oU0?|Rh8)%BND5;_9@9tuM)h5Kcw6}$Ca7H_n)nOf0pd`boCXItb`o11 zb`)@}l6I_h>n+;`g+b^RkYs7;voBz&Gv6FLmyvY|2pS)z#P;t8k;lS>49a$XeVDc4 z(tx2Pe3N%Gd(!wM`E7WRBZy)~vh_vRGt&esDa0NCua)rH#_39*H0!gIXpd>~{rGx+ zJKAeXAZ-z5n=mMVqlM5Km;b;B&KSJlScD8n?2t}kS4Wf9@MjIZSJ2R?&=zQn zs_`=+5J$47&mP4s{Y{TU=~O_LzSrXvEP6W?^pz<#Y*6Fxg@$yUGp31d(h+4x>xpb< zH+R639oDST6F*0iH<9NHC^Ep*8D4-%p2^n-kD6YEI<6GYta6-I;V^ZH3n5}syTD=P z3b6z=jBsdP=FlXcUe@I|%=tY4J_2j!EVNEzph_42iO3yfir|Dh>nFl&Lu9!;`!zJB zCis9?_(%DI?$CA(00pkzw^Up`O;>AnPc(uE$C^a9868t$m?5Q)CR%!crI$YZpiYK6m= z!jv}82He`QKF;10{9@roL2Q7CF)OeY{~dBp>J~X#c-Z~{YLAxNmn~kWQW|2u!Yq00 zl5LKbzl39sVCTpm9eDW_T>Z{x@s6#RH|P zA~_lYas7B@SqI`N=>x50Vj@S)QxouKC(f6Aj zz}7e5e*5n?j@GO;mCYEo^Jp_*BmLt3!N)(T>f#L$XHQWzZEVlJo(>qH@7;c%fy zS-jm^Adju9Sm8rOKTxfTU^!&bg2R!7C_-t+#mKb_K?0R72%26ASF;JWA_prJ8_SVW zOSC7C&CpSrgfXRp8r)QK34g<~!1|poTS7F;)NseFsbwO$YfzEeG3oo!qe#iSxQ2S# z1=Fxc9J;2)pCab-9o-m8%BLjf(*mk#JJX3k9}S7Oq)dV0jG)SOMbw7V^Z<5Q0Cy$< z^U0QUVd4(96W03OA1j|x%{sd&BRqIERDb6W{u1p1{J(a;fd6lnWzjeS`d?L3-0#o7 z{Qv&L7!Tm`9|}u=|IbwS_jgH(_V@o`S*R(-XC$O)DVwF~B&5c~m!zl14ydT6sK+Ly zn+}2hQ4RTC^8YvrQ~vk$f9u=pTN{5H_yTOcza9SVE&nt_{`ZC8zkmFji=UyD`G4~f zUfSTR=Kju>6u+y&|Bylb*W&^P|8fvEbQH3+w*DrKq|9xMzq2OiZyM=;(?>~4+O|jn zC_Et05oc>e%}w4ye2Fm%RIR??VvofwZS-}BL@X=_4jdHp}FlMhW_IW?Zh`4$z*Wr!IzQHa3^?1|);~VaWmsIcmc6 zJs{k0YW}OpkfdoTtr4?9F6IX6$!>hhA+^y_y@vvA_Gr7u8T+i-< zDX(~W5W{8mfbbM-en&U%{mINU#Q8GA`byo)iLF7rMVU#wXXY`a3ji3m{4;x53216i z`zA8ap?>_}`tQj7-%$K78uR}R$|@C2)qgop$}o=g(jOv0ishl!E(R73N=i0~%S)6+ z1xFP7|H0yt3Z_Re*_#C2m3_X{=zi1C&3CM7e?9-Y5lCtAlA%RFG9PDD=Quw1dfYnZ zdUL)#+m`hKx@PT`r;mIx_RQ6Txbti+&;xQorP;$H=R2r)gPMO9>l+!p*Mt04VH$$M zSLwJ81IFjQ5N!S#;MyBD^IS`2n04kuYbZ2~4%3%tp0jn^**BZQ05ELp zY%yntZ=52s6U5Y93Aao)v~M3y?6h7mZcVGp63pK*d&!TRjW99rUU;@s#3kYB76Bs$|LRwkH>L!0Xe zE=dz1o}phhnOVYZFsajQsRA^}IYZnk9Wehvo>gHPA=TPI?2A`plIm8=F1%QiHx*Zn zi)*Y@)$aXW0v1J|#+R2=$ysooHZ&NoA|Wa}htd`=Eud!(HD7JlT8ug|yeBZmpry(W z)pS>^1$N#nuo3PnK*>Thmaxz4pLcY?PP2r3AlhJ7jw(TI8V#c}>Ym;$iPaw+83L+* z!_QWpYs{UWYcl0u z(&(bT0Q*S_uUX9$jC;Vk%oUXw=A-1I+!c18ij1CiUlP@pfP9}CHAVm{!P6AEJ(7Dn z?}u#}g`Q?`*|*_0Rrnu8{l4PP?yCI28qC~&zlwgLH2AkfQt1?B#3AOQjW&10%@@)Q zDG?`6$8?Nz(-sChL8mRs#3z^uOA>~G=ZIG*mgUibWmgd{a|Tn4nkRK9O^37E(()Q% zPR0#M4e2Q-)>}RSt1^UOCGuv?dn|IT3#oW_$S(YR+jxAzxCD_L25p_dt|^>g+6Kgj zJhC8n)@wY;Y7JI6?wjU$MQU|_Gw*FIC)x~^Eq1k41BjLmr}U>6#_wxP0-2Ka?uK14u5M-lAFSX$K1K{WH!M1&q}((MWWUp#Uhl#n_yT5dFs4X`>vmM& z*1!p0lACUVqp&sZG1GWATvZEENs^0_7Ymwem~PlFN3hTHVBv(sDuP;+8iH07a)s(# z%a7+p1QM)YkS7>kbo${k2N1&*%jFP*7UABJ2d||c!eSXWM*<4(_uD7;1XFDod@cT$ zP>IC%^fbC${^QrUXy$f)yBwY^g@}}kngZKa1US!lAa+D=G4wklukaY8AEW%GL zh40pnuv*6D>9`_e14@wWD^o#JvxYVG-~P)+<)0fW zP()DuJN?O*3+Ab!CP-tGr8S4;JN-Ye^9D%(%8d{vb_pK#S1z)nZzE^ezD&%L6nYbZ z*62>?u)xQe(Akd=e?vZbyb5)MMNS?RheZDHU?HK<9;PBHdC~r{MvF__%T)-9ifM#cR#2~BjVJYbA>xbPyl9yNX zX)iFVvv-lfm`d?tbfh^j*A|nw)RszyD<#e>llO8X zou=q3$1|M@Ob;F|o4H0554`&y9T&QTa3{yn=w0BLN~l;XhoslF-$4KGNUdRe?-lcV zS4_WmftU*XpP}*wFM^oKT!D%_$HMT#V*j;9weoOq0mjbl1271$F)`Q(C z76*PAw3_TE{vntIkd=|(zw)j^!@j ^tV@s0U~V+mu)vv`xgL$Z9NQLnuRdZ;95D|1)!0Aybwv}XCE#xz1k?ZC zxAU)v@!$Sm*?)t2mWrkevNFbILU9&znoek=d7jn*k+~ptQ)6z`h6e4B&g?Q;IK+aH z)X(BH`n2DOS1#{AJD-a?uL)@Vl+`B=6X3gF(BCm>Q(9+?IMX%?CqgpsvK+b_de%Q> zj-GtHKf!t@p2;Gu*~#}kF@Q2HMevg~?0{^cPxCRh!gdg7MXsS}BLtG_a0IY0G1DVm z2F&O-$Dzzc#M~iN`!j38gAn`6*~h~AP=s_gy2-#LMFoNZ0<3q+=q)a|4}ur7F#><%j1lnr=F42Mbti zi-LYs85K{%NP8wE1*r4Mm+ZuZ8qjovmB;f##!E*M{*A(4^~vg!bblYi1M@7tq^L8- zH7tf_70iWXqcSQgENGdEjvLiSLicUi3l0H*sx=K!!HLxDg^K|s1G}6Tam|KBV>%YeU)Q>zxQe;ddnDTWJZ~^g-kNeycQ?u242mZs`i8cP)9qW`cwqk)Jf?Re0=SD=2z;Gafh(^X-=WJ$i7Z9$Pao56bTwb+?p>L3bi9 zP|qi@;H^1iT+qnNHBp~X>dd=Us6v#FPDTQLb9KTk%z{&OWmkx3uY(c6JYyK3w|z#Q zMY%FPv%ZNg#w^NaW6lZBU+}Znwc|KF(+X0RO~Q6*O{T-P*fi@5cPGLnzWMSyoOPe3 z(J;R#q}3?z5Ve%crTPZQFLTW81cNY-finw!LH9wr$(C)p_@v?(y#b-R^Pv!}_#7t+A?pHEUMY zoQZIwSETTKeS!W{H$lyB1^!jn4gTD{_mgG?#l1Hx2h^HrpCXo95f3utP-b&%w80F} zXFs@Jp$lbIL64@gc?k*gJ;OForPaapOH7zNMB60FdNP<*9<@hEXJk9Rt=XhHR-5_$Ck-R?+1py&J3Y9^sBBZuj?GwSzua;C@9)@JZpaI zE?x6{H8@j9P06%K_m%9#nnp0Li;QAt{jf-7X%Pd2jHoI4As-9!UR=h6Rjc z!3{UPWiSeLG&>1V5RlM@;5HhQW_&-wL2?%k@dvRS<+@B6Yaj*NG>qE5L*w~1ATP$D zmWu6(OE=*EHqy{($~U4zjxAwpPn42_%bdH9dMphiUU|) z*+V@lHaf%*GcXP079>vy5na3h^>X=n;xc;VFx)`AJEk zYZFlS#Nc-GIHc}j06;cOU@ zAD7Egkw<2a8TOcfO9jCp4U4oI*`|jpbqMWo(={gG3BjuM3QTGDG`%y|xithFck}0J zG}N#LyhCr$IYP`#;}tdm-7^9=72+CBfBsOZ0lI=LC_a%U@(t3J_I1t(UdiJ^@NubM zvvA0mGvTC%{fj53M^|Ywv$KbW;n8B-x{9}Z!K6v-tw&Xe_D2{7tX?eVk$sA*0826( zuGz!K7$O#;K;1w<38Tjegl)PmRso`fc&>fAT5s z7hzQe-_`lx`}2=c)jz6;yn(~F6#M@z_7@Z(@GWbIAo6A2&;aFf&>CVHpqoPh5#~=G zav`rZ3mSL2qwNL+Pg>aQv;%V&41e|YU$!fQ9Ksle!XZERpjAowHtX zi#0lnw{(zmk&}t`iFEMmx-y7FWaE*vA{Hh&>ieZg{5u0-3@a8BY)Z47E`j-H$dadu zIP|PXw1gjO@%aSz*O{GqZs_{ke|&S6hV{-dPkl*V|3U4LpqhG0eVdqfeNX28hrafI zE13WOsRE|o?24#`gQJs@v*EwL{@3>Ffa;knvI4@VEG2I>t-L(KRS0ShZ9N!bwXa}e zI0}@2#PwFA&Y9o}>6(ZaSaz>kw{U=@;d{|dYJ~lyjh~@bBL>n}#@KjvXUOhrZ`DbnAtf5bz3LD@0RpmAyC-4cgu<7rZo&C3~A_jA*0)v|Ctcdu} zt@c7nQ6hSDC@76c4hI&*v|5A0Mj4eQ4kVb0$5j^*$@psB zdouR@B?l6E%a-9%i(*YWUAhxTQ(b@z&Z#jmIb9`8bZ3Um3UW!@w4%t0#nxsc;*YrG z@x$D9Yj3EiA(-@|IIzi@!E$N)j?gedGJpW!7wr*7zKZwIFa>j|cy<(1`VV_GzWN=1 zc%OO)o*RRobvTZE<9n1s$#V+~5u8ZwmDaysD^&^cxynksn!_ypmx)Mg^8$jXu5lMo zK3K_8GJh#+7HA1rO2AM8cK(#sXd2e?%3h2D9GD7!hxOEKJZK&T`ZS0e*c9c36Y-6yz2D0>Kvqy(EuiQtUQH^~M*HY!$e z20PGLb2Xq{3Ceg^sn+99K6w)TkprP)YyNU(+^PGU8}4&Vdw*u;(`Bw!Um76gL_aMT z>*82nmA8Tp;~hwi0d3S{vCwD};P(%AVaBr=yJ zqB?DktZ#)_VFh_X69lAHQw(ZNE~ZRo2fZOIP;N6fD)J*3u^YGdgwO(HnI4pb$H#9) zizJ<>qI*a6{+z=j+SibowDLKYI*Je2Y>~=*fL@i*f&8**s~4l&B&}$~nwhtbOTr=G zFx>{y6)dpJPqv={_@*!q0=jgw3^j`qi@!wiWiT_$1`SPUgaG&9z9u9=m5C8`GpMaM zyMRSv2llS4F}L?233!)f?mvcYIZ~U z7mPng^=p)@Z*Fp9owSYA`Fe4OjLiJ`rdM`-U(&z1B1`S`ufK_#T@_BvenxDQU`deH$X5eMVO=;I4EJjh6?kkG2oc6AYF6|(t)L0$ukG}Zn=c+R`Oq;nC)W^ z{ek!A?!nCsfd_5>d&ozG%OJmhmnCOtARwOq&p!FzWl7M))YjqK8|;6sOAc$w2%k|E z`^~kpT!j+Y1lvE0B)mc$Ez_4Rq~df#vC-FmW;n#7E)>@kMA6K30!MdiC19qYFnxQ* z?BKegU_6T37%s`~Gi2^ewVbciy-m5%1P3$88r^`xN-+VdhhyUj4Kzg2 zlKZ|FLUHiJCZL8&<=e=F2A!j@3D@_VN%z?J;uw9MquL`V*f^kYTrpoWZ6iFq00uO+ zD~Zwrs!e4cqGedAtYxZ76Bq3Ur>-h(m1~@{x@^*YExmS*vw9!Suxjlaxyk9P#xaZK z)|opA2v#h=O*T42z>Mub2O3Okd3GL86KZM2zlfbS z{Vps`OO&3efvt->OOSpMx~i7J@GsRtoOfQ%vo&jZ6^?7VhBMbPUo-V^Znt%-4k{I# z8&X)=KY{3lXlQg4^FH^{jw0%t#2%skLNMJ}hvvyd>?_AO#MtdvH;M^Y?OUWU6BdMX zJ(h;PM9mlo@i)lWX&#E@d4h zj4Z0Czj{+ipPeW$Qtz_A52HA<4$F9Qe4CiNQSNE2Q-d1OPObk4?7-&`={{yod5Iy3kB=PK3%0oYSr`Gca120>CHbC#SqE*ivL2R(YmI1A|nAT?JmK*2qj_3p#?0h)$#ixdmP?UejCg9%AS2 z8I(=_QP(a(s)re5bu-kcNQc-&2{QZ%KE*`NBx|v%K2?bK@Ihz_e<5Y(o(gQ-h+s&+ zjpV>uj~?rfJ!UW5Mop~ro^|FP3Z`@B6A=@f{Wn78cm`)3&VJ!QE+P9&$;3SDNH>hI z_88;?|LHr%1kTX0t*xzG-6BU=LRpJFZucRBQ<^zy?O5iH$t>o}C}Fc+kM1EZu$hm% zTTFKrJkXmCylFgrA;QAA(fX5Sia5TNo z?=Ujz7$Q?P%kM$RKqRQisOexvV&L+bolR%`u`k;~!o(HqgzV9I6w9|g*5SVZN6+kT9H$-3@%h%k7BBnB zPn+wmPYNG)V2Jv`&$LoI*6d0EO^&Nh`E* z&1V^!!Szd`8_uf%OK?fuj~! z%p9QLJ?V*T^)72<6p1ONqpmD?Wm((40>W?rhjCDOz?#Ei^sXRt|GM3ULLnoa8cABQ zA)gCqJ%Q5J%D&nJqypG-OX1`JLT+d`R^|0KtfGQU+jw79la&$GHTjKF>*8BI z0}l6TC@XB6`>7<&{6WX2kX4k+0SaI`$I8{{mMHB}tVo*(&H2SmZLmW* z+P8N>(r}tR?f!O)?)df>HIu>$U~e~tflVmwk*+B1;TuqJ+q_^`jwGwCbCgSevBqj$ z<`Fj*izeO)_~fq%wZ0Jfvi6<3v{Afz;l5C^C7!i^(W>%5!R=Ic7nm(0gJ~9NOvHyA zqWH2-6w^YmOy(DY{VrN6ErvZREuUMko@lVbdLDq*{A+_%F>!@6Z)X9kR1VI1+Ler+ zLUPtth=u~23=CqZoAbQ`uGE_91kR(8Ie$mq1p`q|ilkJ`Y-ob_=Nl(RF=o7k{47*I)F%_XMBz9uwRH8q1o$TkV@8Pwl zzi`^7i;K6Ak7o58a_D-V0AWp;H8pSjbEs$4BxoJkkC6UF@QNL)0$NU;Wv0*5 z0Ld;6tm7eR%u=`hnUb)gjHbE2cP?qpo3f4w%5qM0J*W_Kl6&z4YKX?iD@=McR!gTyhpGGYj!ljQm@2GL^J70`q~4CzPv@sz`s80FgiuxjAZ zLq61rHv1O>>w1qOEbVBwGu4%LGS!!muKHJ#JjfT>g`aSn>83Af<9gM3XBdY)Yql|{ zUds}u*;5wuus)D>HmexkC?;R&*Z`yB4;k;4T*(823M&52{pOd1yXvPJ3PPK{Zs>6w zztXy*HSH0scZHn7qIsZ8y-zftJ*uIW;%&-Ka0ExdpijI&xInDg-Bv-Q#Islcbz+R! zq|xz?3}G5W@*7jSd`Hv9q^5N*yN=4?Lh=LXS^5KJC=j|AJ5Y(f_fC-c4YQNtvAvn|(uP9@5Co{dL z?7|=jqTzD8>(6Wr&(XYUEzT~-VVErf@|KeFpKjh=v51iDYN_`Kg&XLOIG;ZI8*U$@ zKig{dy?1H}UbW%3jp@7EVSD>6c%#abQ^YfcO(`)*HuvNc|j( zyUbYozBR15$nNU$0ZAE%ivo4viW?@EprUZr6oX=4Sc!-WvrpJdF`3SwopKPyX~F>L zJ>N>v=_plttTSUq6bYu({&rkq)d94m5n~Sk_MO*gY*tlkPFd2m=Pi>MK)ObVV@Sgs zmXMNMvvcAuz+<$GLR2!j4w&;{)HEkxl{$B^*)lUKIn&p5_huD6+%WDoH4`p}9mkw$ zXCPw6Y7tc%rn$o_vy>%UNBC`0@+Ih-#T05AT)ooKt?94^ROI5;6m2pIM@@tdT=&WP z{u09xEVdD}{(3v}8AYUyT82;LV%P%TaJa%f)c36?=90z>Dzk5mF2}Gs0jYCmufihid8(VFcZWs8#59;JCn{!tHu5kSBbm zL`F{COgE01gg-qcP2Lt~M9}mALg@i?TZp&i9ZM^G<3`WSDh}+Ceb3Q!QecJ|N;Xrs z{wH{D8wQ2+mEfBX#M8)-32+~q4MRVr1UaSPtw}`iwx@x=1Xv-?UT{t}w}W(J&WKAC zrZ%hssvf*T!rs}}#atryn?LB=>0U%PLwA9IQZt$$UYrSw`7++}WR7tfE~*Qg)vRrM zT;(1>Zzka?wIIz8vfrG86oc^rjM@P7^i8D~b(S23AoKYj9HBC(6kq9g`1gN@|9^xO z{~h zbxGMHqGZ@eJ17bgES?HQnwp|G#7I>@p~o2zxWkgZUYSUeB*KT{1Q z*J3xZdWt`eBsA}7(bAHNcMPZf_BZC(WUR5B8wUQa=UV^e21>|yp+uop;$+#JwXD!> zunhJVCIKgaol0AM_AwJNl}_k&q|uD?aTE@{Q*&hxZ=k_>jcwp}KwG6mb5J*pV@K+- zj*`r0WuEU_8O=m&1!|rj9FG7ad<2px63;Gl z9lJrXx$~mPnuiqIH&n$jSt*ReG}1_?r4x&iV#3e_z+B4QbhHwdjiGu^J3vcazPi`| zaty}NFSWe=TDry*a*4XB)F;KDI$5i9!!(5p@5ra4*iW;FlGFV0P;OZXF!HCQ!oLm1 zsK+rY-FnJ?+yTBd0}{*Y6su|hul)wJ>RNQ{eau*;wWM{vWM`d0dTC-}Vwx6@cd#P? zx$Qyk^2*+_ZnMC}q0)+hE-q)PKoox#;pc%DNJ&D5+if6X4j~p$A7-s&AjDkSEV)aM z(<3UOw*&f)+^5F0Mpzw3zB1ZHl*B?C~Cx) zuNg*>5RM9F5{EpU@a2E7hAE`m<89wbQ2Lz&?Egu-^sglNXG5Q;{9n(%&*kEb0vApd zRHrY@22=pkFN81%x)~acZeu`yvK zovAVJNykgxqkEr^hZksHkpxm>2I8FTu2%+XLs@?ym0n;;A~X>i32{g6NOB@o4lk8{ zB}7Z2MNAJi>9u=y%s4QUXaNdt@SlAZr54!S6^ETWoik6gw=k-itu_}Yl_M9!l+Rbv z(S&WD`{_|SE@@(|Wp7bq1Zq}mc4JAG?mr2WN~6}~u`7M_F@J9`sr0frzxfuqSF~mA z$m$(TWAuCIE99yLSwi%R)8geQhs;6VBlRhJb(4Cx zu)QIF%_W9+21xI45U>JknBRaZ9nYkgAcK6~E|Zxo!B&z9zQhjsi^fgwZI%K@rYbMq znWBXg1uCZ+ljGJrsW7@x3h2 z;kn!J!bwCeOrBx;oPkZ}FeP%wExyf4=XMp)N8*lct~SyfK~4^-75EZFpHYO5AnuRM z!>u?>Vj3+j=uiHc<=cD~JWRphDSwxFaINB42-{@ZJTWe85>-RcQ&U%?wK)vjz z5u5fJYkck##j(bP7W0*RdW#BmAIK`D3=(U~?b`cJ&U2jHj}?w6 z_4BM)#EoJ6)2?pcR4AqBd)qAUn@RtNQq})FIQoBK4ie+GB(Vih2D|Ds>RJo2zE~C- z7mI)7p)5(-O6JRh6a@VZ5~piVC+Xv=O-)=0eTMSJsRE^c1@bPQWlr}E31VqO-%739 zdcmE{`1m;5LH8w|7euK>>>U#Iod8l1yivC>;YWsg=z#07E%cU9x1yw#3l6AcIm%79 zGi^zH6rM#CZMow(S(8dcOq#5$kbHnQV6s?MRsU3et!!YK5H?OV9vf2qy-UHCn>}2d zTwI(A_fzmmCtE@10yAGgU7R&|Fl$unZJ_^0BgCEDE6(B*SzfkapE9#0N6adc>}dtH zJ#nt^F~@JMJg4=Pv}OdUHyPt-<<9Z&c0@H@^4U?KwZM&6q0XjXc$>K3c&3iXLD9_%(?)?2kmZ=Ykb;)M`Tw=%_d=e@9eheGG zk0<`4so}r={C{zr|6+_1mA_=a56(XyJq||g6Es1E6%fPg#l{r+vk9;)r6VB7D84nu zE0Z1EIxH{Y@}hT+|#$0xn+CdMy6Uhh80eK~nfMEIpM z`|G1v!USmx81nY8XkhEOSWto}pc#{Ut#`Pqb}9j$FpzkQ7`0<-@5D_!mrLah98Mpr zz(R7;ZcaR-$aKqUaO!j z=7QT;Bu0cvYBi+LDfE_WZ`e@YaE_8CCxoRc?Y_!Xjnz~Gl|aYjN2&NtT5v4#q3od2 zkCQZHe#bn(5P#J**Fj4Py%SaaAKJsmV6}F_6Z7V&n6QAu8UQ#9{gkq+tB=VF_Q6~^ zf(hXvhJ#tC(eYm6g|I>;55Lq-;yY*COpTp4?J}hGQ42MIVI9CgEC{3hYw#CZfFKVG zgD(steIg8veyqX%pYMoulq zMUmbj8I`t>mC`!kZ@A>@PYXy*@NprM@e}W2Q+s?XIRM-U1FHVLM~c60(yz1<46-*j zW*FjTnBh$EzI|B|MRU11^McTPIGVJrzozlv$1nah_|t4~u}Ht^S1@V8r@IXAkN;lH z_s|WHlN90k4X}*#neR5bX%}?;G`X!1#U~@X6bbhgDYKJK17~oFF0&-UB#()c$&V<0 z7o~Pfye$P@$)Lj%T;axz+G1L_YQ*#(qO zQND$QTz(~8EF1c3<%;>dAiD$>8j@7WS$G_+ktE|Z?Cx<}HJb=!aChR&4z ziD&FwsiZ)wxS4k6KTLn>d~!DJ^78yb>?Trmx;GLHrbCBy|Bip<@sWdAfP0I~;(Ybr zoc-@j?wA!$ zIP0m3;LZy+>dl#&Ymws@7|{i1+OFLYf@+8+)w}n?mHUBCqg2=-Hb_sBb?=q))N7Ej zDIL9%@xQFOA!(EQmchHiDN%Omrr;WvlPIN5gW;u#ByV)x2aiOd2smy&;vA2+V!u|D zc~K(OVI8} z0t|e0OQ7h23e01O;%SJ}Q#yeDh`|jZR7j-mL(T4E;{w^}2hzmf_6PF|`gWVj{I?^2T3MBK>{?nMXed4kgNox2DP!jvP9v`;pa6AV)OD zDt*Vd-x7s{-;E?E5}3p-V;Y#dB-@c5vTWfS7<=>E+tN$ME`Z7K$px@!%{5{uV`cH80|IzU! zDs9=$%75P^QKCRQ`mW7$q9U?mU@vrFMvx)NNDrI(uk>xwO;^($EUvqVev#{W&GdtR z0ew;Iwa}(-5D28zABlC{WnN{heSY5Eq5Fc=TN^9X#R}0z53!xP85#@;2E=&oNYHyo z46~#Sf!1M1X!rh}ioe`>G2SkPH{5nCoP`GT@}rH;-LP1Q7U_ypw4+lwsqiBql80aA zJE<(88yw$`xzNiSnU(hsyJqHGac<}{Av)x9lQ=&py9djsh0uc}6QkmKN3{P!TEy;P zzLDVQj4>+0r<9B0owxBt5Uz`!M_VSS|{(?`_e+qD9b=vZHoo6>?u;!IP zM7sqoyP>kWY|=v06gkhaGRUrO8n@zE?Yh8$om@8%=1}*!2wdIWsbrCg@;6HfF?TEN z+B_xtSvT6H3in#8e~jvD7eE|LTQhO_>3b823&O_l$R$CFvP@3~)L7;_A}JpgN@ax{ z2d9Ra)~Yh%75wsmHK8e87yAn-ZMiLo6#=<&PgdFsJw1bby-j&3%&4=9dQFltFR(VB z@=6XmyNN4yr^^o$ON8d{PQ=!OX17^CrdM~7D-;ZrC!||<+FEOxI_WI3 zCA<35va%4v>gcEX-@h8esj=a4szW7x z{0g$hwoWRQG$yK{@3mqd-jYiVofJE!Wok1*nV7Gm&Ssq#hFuvj1sRyHg(6PFA5U*Q z8Rx>-blOs=lb`qa{zFy&n4xY;sd$fE+<3EI##W$P9M{B3c3Si9gw^jlPU-JqD~Cye z;wr=XkV7BSv#6}DrsXWFJ3eUNrc%7{=^sP>rp)BWKA9<}^R9g!0q7yWlh;gr_TEOD|#BmGq<@IV;ue zg+D2}cjpp+dPf&Q(36sFU&K8}hA85U61faW&{lB`9HUl-WWCG|<1XANN3JVAkRYvr5U z4q6;!G*MTdSUt*Mi=z_y3B1A9j-@aK{lNvxK%p23>M&=KTCgR!Ee8c?DAO2_R?Bkaqr6^BSP!8dHXxj%N1l+V$_%vzHjq zvu7p@%Nl6;>y*S}M!B=pz=aqUV#`;h%M0rUHfcog>kv3UZAEB*g7Er@t6CF8kHDmK zTjO@rejA^ULqn!`LwrEwOVmHx^;g|5PHm#B6~YD=gjJ!043F+&#_;D*mz%Q60=L9O zve|$gU&~As5^uz@2-BfQ!bW)Khn}G+Wyjw-19qI#oB(RSNydn0t~;tAmK!P-d{b-@ z@E5|cdgOS#!>%#Rj6ynkMvaW@37E>@hJP^82zk8VXx|3mR^JCcWdA|t{0nPmYFOxN z55#^-rlqobcr==<)bi?E?SPymF*a5oDDeSdO0gx?#KMoOd&G(2O@*W)HgX6y_aa6i zMCl^~`{@UR`nMQE`>n_{_aY5nA}vqU8mt8H`oa=g0SyiLd~BxAj2~l$zRSDHxvDs; zI4>+M$W`HbJ|g&P+$!U7-PHX4RAcR0szJ*(e-417=bO2q{492SWrqDK+L3#ChUHtz z*@MP)e^%@>_&#Yk^1|tv@j4%3T)diEXATx4K*hcO`sY$jk#jN5WD<=C3nvuVs zRh||qDHnc~;Kf59zr0;c7VkVSUPD%NnnJC_l3F^#f_rDu8l}l8qcAz0FFa)EAt32I zUy_JLIhU_J^l~FRH&6-iv zSpG2PRqzDdMWft>Zc(c)#tb%wgmWN%>IOPmZi-noqS!^Ft zb81pRcQi`X#UhWK70hy4tGW1mz|+vI8c*h@fFGJtW3r>qV>1Z0r|L>7I3un^gcep$ zAAWfZHRvB|E*kktY$qQP_$YG60C z@X~tTQjB3%@`uz!qxtxF+LE!+=nrS^07hn`EgAp!h|r03h7B!$#OZW#ACD+M;-5J!W+{h z|6I;5cNnE(Y863%1(oH}_FTW})8zYb$7czPg~Szk1+_NTm6SJ0MS_|oSz%e(S~P-& zSFp;!k?uFayytV$8HPwuyELSXOs^27XvK-DOx-Dl!P|28DK6iX>p#Yb%3`A&CG0X2 zS43FjN%IB}q(!hC$fG}yl1y9W&W&I@KTg6@K^kpH8=yFuP+vI^+59|3%Zqnb5lTDAykf9S#X`3N(X^SpdMyWQGOQRjhiwlj!0W-yD<3aEj^ z&X%=?`6lCy~?`&WSWt?U~EKFcCG_RJ(Qp7j=$I%H8t)Z@6Vj zA#>1f@EYiS8MRHZphpMA_5`znM=pzUpBPO)pXGYpQ6gkine{ z6u_o!P@Q+NKJ}k!_X7u|qfpAyIJb$_#3@wJ<1SE2Edkfk9C!0t%}8Yio09^F`YGzp zaJHGk*-ffsn85@)%4@`;Fv^8q(-Wk7r=Q8pT&hD`5(f?M{gfzGbbwh8(}G#|#fDuk z7v1W)5H9wkorE0ZZjL0Q1=NRGY>zwgfm81DdoaVwNH;or{{e zSyybt)m<=zXoA^RALYG-2touH|L*BLvmm9cdMmn+KGopyR@4*=&0 z&4g|FLoreZOhRmh=)R0bg~T2(8V_q7~42-zvb)+y959OAv!V$u(O z3)%Es0M@CRFmG{5sovIq4%8Ahjk#*5w{+)+MWQoJI_r$HxL5km1#6(e@{lK3Udc~n z0@g`g$s?VrnQJ$!oPnb?IHh-1qA`Rz$)Ai<6w$-MJW-gKNvOhL+XMbE7&mFt`x1KY z>k4(!KbbpZ`>`K@1J<(#vVbjx@Z@(6Q}MF#Mnbr-f55)vXj=^j+#)=s+ThMaV~E`B z8V=|W_fZWDwiso8tNMTNse)RNBGi=gVwgg%bOg8>mbRN%7^Um-7oj4=6`$|(K7!+t^90a{$1 z8Z>}<#!bm%ZEFQ{X(yBZMc>lCz0f1I2w9SquGh<9<=AO&g6BZte6hn>Qmvv;Rt)*c zJfTr2=~EnGD8P$v3R|&1RCl&7)b+`=QGapiPbLg_pxm`+HZurtFZ;wZ=`Vk*do~$wBxoW&=j0OTbQ=Q%S8XJ%~qoa3Ea|au5 zo}_(P;=!y z-AjFrERh%8la!z6Fn@lR?^E~H12D? z8#ht=1F;7@o4$Q8GDj;sSC%Jfn01xgL&%F2wG1|5ikb^qHv&9hT8w83+yv&BQXOQy zMVJSBL(Ky~p)gU3#%|blG?I zR9rP^zUbs7rOA0X52Ao=GRt@C&zlyjNLv-}9?*x{y(`509qhCV*B47f2hLrGl^<@S zuRGR!KwHei?!CM10pBKpDIoBNyRuO*>3FU?HjipIE#B~y3FSfOsMfj~F9PNr*H?0o zHyYB^G(YyNh{SxcE(Y-`x5jFMKb~HO*m+R%rq|ic4fzJ#USpTm;X7K+E%xsT_3VHK ze?*uc4-FsILUH;kL>_okY(w`VU*8+l>o>JmiU#?2^`>arnsl#)*R&nf_%>A+qwl%o z{l(u)M?DK1^mf260_oteV3#E_>6Y4!_hhVDM8AI6MM2V*^_M^sQ0dmHu11fy^kOqX zqzps-c5efIKWG`=Es(9&S@K@)ZjA{lj3ea7_MBPk(|hBFRjHVMN!sNUkrB;(cTP)T97M$ z0Dtc&UXSec<+q?y>5=)}S~{Z@ua;1xt@=T5I7{`Z=z_X*no8s>mY;>BvEXK%b`a6(DTS6t&b!vf_z#HM{Uoy z_5fiB(zpkF{})ruka$iX*~pq1ZxD?q68dIoIZSVls9kFGsTwvr4{T_LidcWtt$u{k zJlW7moRaH6+A5hW&;;2O#$oKyEN8kx z`LmG)Wfq4ykh+q{I3|RfVpkR&QH_x;t41UwxzRFXt^E2B$domKT@|nNW`EHwyj>&< zJatrLQ=_3X%vd%nHh^z@vIk(<5%IRAa&Hjzw`TSyVMLV^L$N5Kk_i3ey6byDt)F^U zuM+Ub4*8+XZpnnPUSBgu^ijLtQD>}K;eDpe1bNOh=fvIfk`&B61+S8ND<(KC%>y&? z>opCnY*r5M+!UrWKxv0_QvTlJc>X#AaI^xoaRXL}t5Ej_Z$y*|w*$6D+A?Lw-CO-$ zitm^{2Ct82-<0IW)0KMNvJHgBrdsIR0v~=H?n6^}l{D``Me90`^o|q!olsF?UX3YS zq^6Vu>Ijm>>PaZI8G@<^NGw{Cx&%|PwYrfwR!gX_%AR=L3BFsf8LxI|K^J}deh0Zd zV?$3r--FEX`#INxsOG6_=!v)DI>0q|BxT)z-G6kzA01M?rba+G_mwNMQD1mbVbNTW zmBi*{s_v_Ft9m2Avg!^78(QFu&n6mbRJ2bAv!b;%yo{g*9l2)>tsZJOOp}U~8VUH`}$8p_}t*XIOehezolNa-a2x0BS})Y9}& z*TPgua{Ewn-=wVrmJUeU39EKx+%w%=ixQWKDLpwaNJs65#6o7Ln7~~X+p_o2BR1g~ zVCfxLzxA{HlWAI6^H;`juI=&r1jQrUv_q0Z1Ja-tjdktrrP>GOC*#p?*xfQU5MqjM zsBe!9lh(u8)w$e@Z|>aUHI5o;MGw*|Myiz3-f0;pHg~Q#%*Kx8MxH%AluVXjG2C$) zWL-K63@Q`#y9_k_+}eR(x4~dp7oV-ek0H>Igy8p#i4GN{>#v=pFYUQT(g&b$OeTy- zX_#FDgNF8XyfGY6R!>inYn8IR2RDa&O!(6NIHrC0H+Qpam1bNa=(`SRKjixBTtm&e z`j9porEci!zdlg1RI0Jw#b(_Tb@RQK1Zxr_%7SUeH6=TrXt3J@js`4iDD0=I zoHhK~I7^W8^Rcp~Yaf>2wVe|Hh1bXa_A{oZ9eG$he;_xYvTbTD#moBy zY57-f2Ef1TP^lBi&p5_s7WGG9|0T}dlfxOxXvScJO1Cnq`c`~{Dp;{;l<-KkCDE+p zmexJkd}zCgE{eF=)K``-qC~IT6GcRog_)!X?fK^F8UDz$(zFUrwuR$qro5>qqn>+Z z%<5>;_*3pZ8QM|yv9CAtrAx;($>4l^_$_-L*&?(77!-=zvnCVW&kUcZMb6;2!83si z518Y%R*A3JZ8Is|kUCMu`!vxDgaWjs7^0j(iTaS4HhQ)ldR=r)_7vYFUr%THE}cPF z{0H45FJ5MQW^+W>P+eEX2kLp3zzFe*-pFVAdDZRybv?H|>`9f$AKVjFWJ=wegO7hO zOIYCtd?Vj{EYLT*^gl35|HbMX|NAEUf2ra9dy1=O;figB>La=~eA^#>O6n4?EMugV zbbt{Dbfef5l^(;}5kZ@!XaWwF8z0vUr6r|+QN*|WpF z^*osUHzOnE$lHuWYO$G7>}Y)bY0^9UY4eDV`E{s+{}Z$O$2*lMEYl zTA`ki(<0(Yrm~}15V-E^e2W6`*`%ydED-3G@$UFm6$ZtLx z+av`BhsHcAWqdxPWfu2*%{}|Sptax4_=NpDMeWy$* zZM6__s`enB$~0aT1BU^2k`J9F%+n+lL_|8JklWOCVYt*0%o*j4w1CsB_H^tVpYT_LLyKuyk=CV6~1M<7~^FylL*+AIFf3h>J=x$ygY-BG}4LJ z8XxYPY!v7dO3PVwEoY=`)6krokmR^|Mg5ztX_^#QR}ibr^X-|_St#rtv3gukh0(#A=};NPlNz57ZDFJ9hf#NP50zS)+Fo=StX)i@ zWS?W}i6LjB>kAB~lupAPyIjFb)izFgRq*iS*(Jt509jNr3r72{Gj`5DGoj;J&k5G@Rm!dJ($ox>SbxR)fc zz|Phug;~A7!p@?|mMva@rWuf2fSDK_ZxN3vVmlYz>rrf?LpiNs)^z!y{As@`55JC~ zS*GD3#N-ptY!2<613UelAJ;M4EEI$dm)`8#n$|o{ce^dlyoUY3bsy2hgnj-;ovubb zg2h1rZA6Ot}K_cpYBpIuF&CyK~5R0Wv;kG|3A^8K3nk{rw$Be8u@aos#qvKQKJyVU$cX6biw&Ep#+q7upFX z%qo&`WZ){<%zh@BTl{MO@v9#;t+cb7so0Uz49Fmo1e4>y!vUyIHadguZS0T7-x#_drMXz*16*c zymR0u^`ZQpXN}2ofegbpSedL%F9aypdQcrzjzPlBW0j zMlPzC&ePZ@Cq!?d%9oQNEg0`rHALm8l#lUdXMVEqDvb(AID~H(?H9z!e9G98fG@IzhajKr)3{L_Clu1(Bwg`RM!-(MOuZi zbeDsj9I3(~EITsE=3Z)a|l_rn8W92U0DB70gF7YYfO0j!)h?QobY1lSR>0 z_TVw@$eP~3k8r9;%g%RlZzCJ2%f}DvY`rsZ$;ak&^~-`i%B%+O!pnADeVyV!dHj|} zzOj#q4eRx9Q8c2Z7vy9L&fGLj+3_?fp}+8o`Xpwyi(81H|7P8#65%FIS*lOi={o&v z4NV$xu7az4Nb50dRGZv<tdZCx4Ek<_o3!mAT} zL5l*|K3Qr-)W8paaG z&R6{ped_4e2cy}ejD0!dt{*PaC*^L@eB%(1Fmc%Y#4)~!jF#lCGfj#E??4LG-T;!M z>Uha}f;W>ib_ZL-I7-v9KZQls^G!-JmL^w;=^}?!RXK;m4$#MwI2AH-l7M2-0 zVMK8k^+4+>2S0k^N_40EDa#`7c;2!&3-o6MHsnBfRnq@>E@)=hDulVq-g5SQWDWbt zj6H5?QS2gRZ^Zvbs~cW|8jagJV|;^zqC0e=D1oUsQPJ3MCb+eRGw(XgIY9y8v_tXq z9$(xWntWpx_Uronmvho{JfyYdV{L1N$^s^|-Nj`Ll`lUsiWTjm&8fadUGMXreJGw$ zQ**m+Tj|(XG}DyUKY~2?&9&n6SJ@9VKa9Hcayv{ar^pNr0WHy zP$bQv&8O!vd;GoT!pLwod-42qB^`m!b7nP@YTX}^+1hzA$}LSLh}Ln|?`%8xGMazw z8WT!LoYJ-Aq3=2p6ZSP~uMgSSWv3f`&-I06tU}WhZsA^6nr&r17hjQIZE>^pk=yZ% z06}dfR$85MjWJPq)T?OO(RxoaF+E#4{Z7)i9}Xsb;Nf+dzig61HO;@JX1Lf9)R5j9)Oi6vPL{H z&UQ9ln=$Q8jnh6-t;`hKM6pHftdd?$=1Aq16jty4-TF~`Gx=C&R242uxP{Y@Q~%O3 z*(16@x+vJsbW@^3tzY=-5MHi#(kB};CU%Ep`mVY1j$MAPpYJBB3x$ue`%t}wZ-@CG z(lBv36{2HMjxT)2$n%(UtHo{iW9>4HX4>)%k8QNnzIQYXrm-^M%#Qk%9odbUrZDz1YPdY`2Z4w~p!5tb^m(mUfk}kZ9+EsmenQ)5iwiaulcy zCJ#2o4Dz?@%)aAKfVXYMF;3t@aqNh2tBBlBkCdj`F31b=h93y(46zQ-YK@+zX5qM9 z&=KkN&3@Ptp*>UD$^q-WpG|9O)HBXz{D>p!`a36aPKkgz7uxEo0J>-o+4HHVD9!Hn z${LD0d{tuGsW*wvZoHc8mJroAs(3!FK@~<}Pz1+vY|Gw}Lwfxp{4DhgiQ_SSlV)E| zZWZxYZLu2EB1=g_y@(ieCQC_1?WNA0J0*}eMZfxCCs>oL;?kHdfMcKB+A)Qull$v( z2x6(38utR^-(?DG>d1GyU()8>ih3ud0@r&I$`ZSS<*1n6(76=OmP>r_JuNCdS|-8U zxGKXL1)Lc2kWY@`_kVBt^%7t9FyLVYX(g%a6>j=yURS1!V<9ieT$$5R+yT!I>}jI5 z?fem|T=Jq;BfZmsvqz_Ud*m5;&xE66*o*S22vf-L+MosmUPPA}~wy`kntf8rIeP-m;;{`xe}9E~G7J!PYoVH_$q~NzQab?F8vWUja5BJ!T5%5IpyqI#Dkps0B;gQ*z?c#N>spFw|wRE$gY?y4wQbJ zku2sVLh({KQz6e0yo+X!rV#8n8<;bHWd{ZLL_(*9Oi)&*`LBdGWz>h zx+p`Wi00u#V$f=CcMmEmgFjw+KnbK3`mbaKfoCsB{;Q^oJgj*LWnd_(dk9Kcssbj` z?*g8l`%{*LuY!Ls*|Tm`1Gv-tRparW8q4AK(5pfJFY5>@qO( zcY>pt*na>LlB^&O@YBDnWLE$x7>pMdSmb-?qMh79eB+Wa{)$%}^kX@Z3g>fytppz! zl%>pMD(Yw+5=!UgYHLD69JiJ;YhiGeEyZM$Au{ff;i zCBbNQfO{d!b7z^F732XX&qhEsJA1UZtJjJEIPyDq+F`LeAUU_4`%2aTX#3NG3%W8u zC!7OvlB?QJ4s2#Ok^_8SKcu&pBd}L?vLRT8Kow#xARt`5&Cg=ygYuz>>c z4)+Vv$;<$l=is&E{k&4Lf-Lzq#BHuWc;wDfm4Fbd5Sr!40s{UpKT$kzmUi{V0t1yp zPOf%H8ynE$x@dQ_!+ISaI}#%72UcYm7~|D*(Fp8xiFAj$CmQ4oH3C+Q8W=Y_9Sp|B z+k<%5=y{eW=YvTivV(*KvC?qxo)xqcEU9(Te=?ITts~;xA0Jph-vpd4@Zw#?r2!`? zB3#XtIY^wxrpjJv&(7Xjvm>$TIg2ZC&+^j(gT0R|&4cb)=92-2Hti1`& z=+M;*O%_j3>9zW|3h{0Tfh5i)Fa;clGNJpPRcUmgErzC{B+zACiPHbff3SmsCZ&X; zp=tgI=zW-t(5sXFL8;ITHw0?5FL3+*z5F-KcLN130l=jAU6%F=DClRPrzO|zY+HD`zlZ-)JT}X?2g!o zxg4Ld-mx6&*-N0-MQ(z+zJo8c`B39gf{-h2vqH<=^T&o1Dgd>4BnVht+JwLcrjJl1 zsP!8`>3-rSls07q2i1hScM&x0lQyBbk(U=#3hI7Bkh*kj6H*&^p+J?OMiT_3*vw5R zEl&p|QQHZq6f~TlAeDGy(^BC0vUK?V&#ezC0*#R-h}_8Cw8-*${mVfHssathC8%VA zUE^Qd!;Rvym%|f@?-!sEj|73Vg8!$$zj_QBZAOraF5HCFKl=(Ac|_p%-P;6z<2WSf zz(9jF2x7ZR{w+p)ETCW06PVt0YnZ>gW9^sr&~`%a_7j-Ful~*4=o|&TM@k@Px2z>^ t{*Ed16F~3V5p+(suF-++X8+nHtT~NSfJ>UC3v)>lEpV}<+rIR_{{yMcG_L>v diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5c82cb0..260504c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/sdmx-json10/build.gradle b/sdmx-json10/build.gradle new file mode 100644 index 0000000..39a8878 --- /dev/null +++ b/sdmx-json10/build.gradle @@ -0,0 +1,49 @@ +plugins { + id 'java' +} + +repositories { + mavenCentral() +} + +dependencies { + implementation project(":sdmx30-serializer") + implementation project(":sdmx30-infomodel") + + compileOnly("org.projectlombok:lombok:${lombok_version}") + annotationProcessor("org.projectlombok:lombok:${lombok_version}") + + implementation("org.apache.logging.log4j:log4j-slf4j2-impl:${log4j_version}") + implementation("org.apache.logging.log4j:log4j-core:${log4j_version}") + implementation("com.epam.deltix:SdmxDataParser:${sdmx_version}") + + implementation("org.apache.commons:commons-collections4:${org_apache_commons_commons_collections4_version}") + implementation("org.apache.commons:commons-lang3:${org_apache_commons_commons_lang3_version}") + implementation("com.fasterxml.jackson.core:jackson-core:${fasterxml_version}") + implementation("com.fasterxml.jackson.core:jackson-databind:${fasterxml_databind_version}") + implementation("com.google.guava:guava:${guava_version}") + + testImplementation("org.projectlombok:lombok:${lombok_version}") + testAnnotationProcessor("org.projectlombok:lombok:${lombok_version}") + + testImplementation("org.jsonschema2pojo:jsonschema2pojo-core:${jsonschema2pojo_version}") + testImplementation("io.github.benas:random-beans:${random_beans_version}") + testImplementation("org.assertj:assertj-core:${assertj_version}") + testImplementation("net.javacrumbs.json-unit:json-unit:${json_unit_version}") + testImplementation("net.javacrumbs.json-unit:json-unit-assertj:${json_unit_version}") + testImplementation("org.mockito:mockito-core:${mockito_version}") + + testImplementation("com.epam.deltix:SdmxApi:${sdmx_version}") + testImplementation("com.epam.deltix:SdmxBeans:${sdmx_version}") + testImplementation("com.epam.deltix:SdmxDataParser:${sdmx_version}") + testImplementation("com.epam.deltix:SdmxFileQueryProcessor:${sdmx_version}") + testImplementation("com.epam.deltix:SdmxQueryBuilder:${sdmx_version}") + testImplementation("com.epam.deltix:SdmxSourceUtil:${sdmx_version}") + testImplementation("com.epam.deltix:SdmxStructureParser:${sdmx_version}") + testImplementation("com.epam.deltix:SdmxStructureRetrieval:${sdmx_version}") + testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.3' +} + +test { + useJUnitPlatform() +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/AgencySchemeWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/AgencySchemeWriter.java new file mode 100644 index 0000000..fe888f7 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/AgencySchemeWriter.java @@ -0,0 +1,42 @@ +package com.epam.jsdmx.json10.structure.writer; + + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.AgencyScheme; +import com.epam.jsdmx.infomodel.sdmx30.AgencySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class AgencySchemeWriter extends MaintainableWriter { + + private final OrganisationWriter organisationWriter; + + public AgencySchemeWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + OrganisationWriter organisationWriter) { + super(versionableWriter, linksWriter); + this.organisationWriter = organisationWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, AgencyScheme artefact) throws IOException { + AgencySchemeImpl agencyScheme = (AgencySchemeImpl) artefact; + agencyScheme.setId(StructureUtils.AGENCIES_ID); + super.writeFields(jsonGenerator, agencyScheme); + jsonGenerator.writeBooleanField(StructureUtils.IS_PARTIAL, agencyScheme.isPartial()); + organisationWriter.writeOrganisation(jsonGenerator, artefact.getItems(), StructureUtils.AGENCIES); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getAgencySchemes(); + } + + @Override + protected String getArrayName() { + return StructureUtils.AGENCY_SCHEMES; + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/AnnotableWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/AnnotableWriter.java new file mode 100644 index 0000000..e2e815d --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/AnnotableWriter.java @@ -0,0 +1,44 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.AnnotableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.Annotation; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; + +@RequiredArgsConstructor +public class AnnotableWriter { + + private final LinksWriter linksWriter; + + public void write(JsonGenerator jsonGenerator, T annotableArtefact) throws IOException { + write(jsonGenerator, annotableArtefact.getAnnotations()); + } + + protected void write(JsonGenerator jsonGenerator, List annotations) throws IOException { + if (CollectionUtils.isEmpty(annotations)) { + return; + } + jsonGenerator.writeFieldName(StructureUtils.ANNOTATIONS); + jsonGenerator.writeStartArray(); + for (Annotation annotation : annotations) { + writeAnnotation(jsonGenerator, annotation); + } + jsonGenerator.writeEndArray(); + } + + private void writeAnnotation(JsonGenerator jg, Annotation annotation) throws IOException { + jg.writeStartObject(); + StructureUtils.writeStringField(jg, StructureUtils.ID, annotation.getId()); + StructureUtils.writeStringField(jg, StructureUtils.TITLE, annotation.getTitle()); + StructureUtils.writeStringField(jg, StructureUtils.TYPE, annotation.getType()); + StructureUtils.writeStringField(jg, StructureUtils.TEXT, (annotation.getText() != null) ? annotation.getText().getForDefaultLocale() : null); + StructureUtils.writeInternationalString(jg, annotation.getText(), StructureUtils.TEXTS); + linksWriter.writeLinks(jg, annotation.getUrl()); + jg.writeEndObject(); + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/AttributeListWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/AttributeListWriter.java new file mode 100644 index 0000000..61f1516 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/AttributeListWriter.java @@ -0,0 +1,111 @@ +package com.epam.jsdmx.json10.structure.writer; + +import static com.epam.jsdmx.json10.structure.writer.StructureUtils.writeStringField; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.AttributeRelationship; +import com.epam.jsdmx.infomodel.sdmx30.DataAttribute; +import com.epam.jsdmx.infomodel.sdmx30.DimensionRelationship; +import com.epam.jsdmx.infomodel.sdmx30.GroupRelationship; +import com.epam.jsdmx.infomodel.sdmx30.ObservationRelationship; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.EqualsAndHashCode; +import org.apache.commons.collections4.CollectionUtils; + +@EqualsAndHashCode(callSuper = false) +public class AttributeListWriter { + + private final IdentifiableWriter identifiableWriter; + private final ConceptRoleWriter conceptRoleWriter; + private final ComponentWriter componentWriter; + + public AttributeListWriter(IdentifiableWriter identifiableWriter, + ConceptRoleWriter conceptRoleWriter, + ComponentWriter componentWriter) { + this.identifiableWriter = identifiableWriter; + this.conceptRoleWriter = conceptRoleWriter; + this.componentWriter = componentWriter; + } + + public void write(JsonGenerator jsonGenerator, AttributeDescriptor attributeDescriptor) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.ATTRIBUTE_LIST); + if (attributeDescriptor == null || attributeDescriptor.getComponents().isEmpty()) { + jsonGenerator.writeNull(); + return; + } + + AttributeDescriptorImpl attributeDescriptorImpl = (AttributeDescriptorImpl) attributeDescriptor; + attributeDescriptorImpl.setId(StructureUtils.ATTRIBUTE_DESCRIPTOR_ID); + + jsonGenerator.writeStartObject(); + identifiableWriter.write(jsonGenerator, attributeDescriptorImpl); + + writeDataAttributes(jsonGenerator, attributeDescriptorImpl.getComponents()); + + jsonGenerator.writeEndObject(); + } + + private void writeDataAttributes(JsonGenerator jsonGenerator, List attributeDescriptorComponents) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.ATTRIBUTES); + jsonGenerator.writeStartArray(); + if (attributeDescriptorComponents != null && !attributeDescriptorComponents.isEmpty()) { + for (DataAttribute dataAttribute : attributeDescriptorComponents) { + if (dataAttribute != null) { + jsonGenerator.writeStartObject(); + componentWriter.write(jsonGenerator, dataAttribute); + writeAssignmentStatus(jsonGenerator, dataAttribute.isMandatory()); + conceptRoleWriter.write(jsonGenerator, dataAttribute.getConceptRoles()); + writeAttributeRelationship(jsonGenerator, dataAttribute.getAttributeRelationship()); + jsonGenerator.writeEndObject(); + } + } + } + jsonGenerator.writeEndArray(); + } + + private void writeAssignmentStatus(JsonGenerator jg, boolean mandatory) { + writeStringField(jg, "assignmentStatus", mandatory ? "Mandatory" : "Conditional"); + } + + private void writeAttributeRelationship(JsonGenerator jg, AttributeRelationship attributeRelationship) throws IOException { + jg.writeFieldName(StructureUtils.ATTRIBUTE_RELATIONSHIP); + jg.writeStartObject(); + if (attributeRelationship instanceof DimensionRelationship) { + DimensionRelationship dimensionRelationship = (DimensionRelationship) attributeRelationship; + jg.writeFieldName(StructureUtils.DIMENSIONS); + List dimensions = dimensionRelationship.getDimensions(); + jg.writeStartArray(); + for (String dimension : dimensions) { + jg.writeString(dimension); + } + jg.writeEndArray(); + + List groupKeys = dimensionRelationship.getGroupKeys(); + if (CollectionUtils.isNotEmpty(groupKeys)) { + jg.writeFieldName(StructureUtils.ATTACHMENT_GROUPS); + jg.writeStartArray(); + for (String groupKey : groupKeys) { + jg.writeString(groupKey); + } + jg.writeEndArray(); + } + + } else if (attributeRelationship instanceof ObservationRelationship) { + writeStringField(jg, "primaryMeasure", "OBS_VALUE"); + } else if (attributeRelationship instanceof GroupRelationship) { + GroupRelationship groupRelationship = (GroupRelationship) attributeRelationship; + jg.writeStringField(StructureUtils.GROUP, groupRelationship.getGroupKey()); + } else { + jg.writeFieldName(StructureUtils.NONE); + jg.writeStartObject(); + jg.writeEndObject(); + } + jg.writeEndObject(); + } + +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/BaseWriterJson.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/BaseWriterJson.java new file mode 100644 index 0000000..80d0a47 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/BaseWriterJson.java @@ -0,0 +1,20 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.OutputStream; + +import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; + +public class BaseWriterJson { + + protected final JsonGenerator jsonGenerator; + + @SneakyThrows + protected BaseWriterJson(ObjectMapper mapper, + OutputStream outputStream) { + this.jsonGenerator = mapper.getFactory().createGenerator(outputStream, JsonEncoding.UTF8); + } + +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CategorisationWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CategorisationWriter.java new file mode 100644 index 0000000..b12256a --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CategorisationWriter.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Categorisation; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; +import com.epam.jsdmx.serializer.sdmx21.ReferenceResolver; + +import com.fasterxml.jackson.core.JsonGenerator; + + +public class CategorisationWriter extends MaintainableWriter { + + private final ReferenceResolver referenceResolver; + private final ReferenceAdapter referenceAdapter; + + public CategorisationWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + ReferenceResolver referenceResolver, + ReferenceAdapter referenceAdapter) { + super(versionableWriter, linksWriter); + this.referenceResolver = referenceResolver; + this.referenceAdapter = referenceAdapter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, Categorisation categorisation) throws IOException { + super.writeFields(jsonGenerator, categorisation); + writeArtefactReference(jsonGenerator, categorisation.getCategorizedArtefact(), StructureUtils.SOURCE); + writeArtefactReference(jsonGenerator, categorisation.getCategorizedBy(), StructureUtils.TARGET); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getCategorisations(); + } + + @Override + protected String getArrayName() { + return StructureUtils.CATEGORISATIONS; + } + + private void writeArtefactReference(JsonGenerator jsonGenerator, ArtefactReference structure, String fieldName) + throws IOException { + if (structure != null) { + final ArtefactReference resolved = referenceResolver.resolve(structure); + jsonGenerator.writeStringField(fieldName, referenceAdapter.toAdaptedUrn(resolved)); + } + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CategorySchemeWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CategorySchemeWriter.java new file mode 100644 index 0000000..f4c5eec --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CategorySchemeWriter.java @@ -0,0 +1,56 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Category; +import com.epam.jsdmx.infomodel.sdmx30.CategoryScheme; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class CategorySchemeWriter extends MaintainableWriter { + + private final NameableWriter nameableWriter; + + public CategorySchemeWriter(VersionableWriter versionableWriter, LinksWriter linksWriter, NameableWriter nameableWriter) { + super(versionableWriter, linksWriter); + this.nameableWriter = nameableWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, CategoryScheme categoryScheme) throws IOException { + super.writeFields(jsonGenerator, categoryScheme); + jsonGenerator.writeBooleanField(StructureUtils.IS_PARTIAL, categoryScheme.isPartial()); + writeCategoriesList(jsonGenerator, categoryScheme.getItems()); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getCategorySchemes(); + } + + @Override + protected String getArrayName() { + return StructureUtils.CATEGORY_SCHEMES; + } + + private void writeCategoriesList(JsonGenerator jsonGenerator, List categoryScheme) throws IOException { + if (categoryScheme != null) { + jsonGenerator.writeFieldName(StructureUtils.CATEGORIES); + jsonGenerator.writeStartArray(); + if (!categoryScheme.isEmpty()) { + for (Category category : categoryScheme) { + jsonGenerator.writeStartObject(); + nameableWriter.write(jsonGenerator, category); + if (!category.getHierarchy().isEmpty()) { + writeCategoriesList(jsonGenerator, category.getHierarchy()); + } + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CodeWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CodeWriter.java new file mode 100644 index 0000000..9a5e8e8 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CodeWriter.java @@ -0,0 +1,43 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Code; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections4.CollectionUtils; + +public interface CodeWriter { + + default void writeCodes(JsonGenerator jsonGenerator, + List codes, + String name, + NameableWriter nameableWriter) throws IOException { + if (CollectionUtils.isNotEmpty(codes)) { + jsonGenerator.writeFieldName(name); + jsonGenerator.writeStartArray(); + for (T code : codes) { + write(jsonGenerator, code, nameableWriter); + } + jsonGenerator.writeEndArray(); + } + } + + default void write(JsonGenerator jsonGenerator, + T code, + NameableWriter nameableWriter) throws IOException { + jsonGenerator.writeStartObject(); + writeFields(jsonGenerator, code, nameableWriter); + jsonGenerator.writeEndObject(); + } + + default void writeFields(JsonGenerator jsonGenerator, + T code, + NameableWriter nameableWriter) throws IOException { + nameableWriter.write(jsonGenerator, code); + if (code.getParentId() != null) { + jsonGenerator.writeStringField(StructureUtils.PARENT, code.getParentId()); + } + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CodeWriterImpl.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CodeWriterImpl.java new file mode 100644 index 0000000..e8496ae --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CodeWriterImpl.java @@ -0,0 +1,6 @@ +package com.epam.jsdmx.json10.structure.writer; + +import com.epam.jsdmx.infomodel.sdmx30.Code; + +public class CodeWriterImpl implements CodeWriter { +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CodelistWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CodelistWriter.java new file mode 100644 index 0000000..e418068 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CodelistWriter.java @@ -0,0 +1,50 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.Optional; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Codelist; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class CodelistWriter extends MaintainableWriter { + + private final CodeWriterImpl codeWriter; + private final NameableWriter nameableWriter; + + public CodelistWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + CodeWriterImpl codeWriter, + NameableWriter nameableWriter) { + super(versionableWriter, linksWriter); + this.codeWriter = codeWriter; + this.nameableWriter = nameableWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, Codelist codelist) throws IOException { + super.writeFields(jsonGenerator, codelist); + jsonGenerator.writeBooleanField(StructureUtils.IS_PARTIAL, codelist.isPartial()); + codeWriter.writeCodes(jsonGenerator, codelist.getItems(), StructureUtils.CODES, nameableWriter); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getCodelists(); + } + + @Override + protected String getArrayName() { + return StructureUtils.CODE_LISTS; + } + + @Override + public Optional getWritableArtefactStructureClass() { + return Optional.of(StructureClassImpl.CODELIST); + } + +} \ No newline at end of file diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ComponentWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ComponentWriter.java new file mode 100644 index 0000000..bfe54c9 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ComponentWriter.java @@ -0,0 +1,37 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Component; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.serializer.sdmx21.ReferenceResolver; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class ComponentWriter { + + private final IdentifiableWriter identifiableWriter; + private final RepresentationWriter representationWriter; + private final ReferenceResolver referenceResolver; + + public ComponentWriter(IdentifiableWriter identifiableWriter, + RepresentationWriter representationWriter, + ReferenceResolver referenceResolver) { + this.identifiableWriter = identifiableWriter; + this.representationWriter = representationWriter; + this.referenceResolver = referenceResolver; + } + + public void write(JsonGenerator jsonGenerator, Component component) throws IOException { + identifiableWriter.write(jsonGenerator, component); + if (component.getConceptIdentity() != null) { + final ArtefactReference ref = component.getConceptIdentity(); + jsonGenerator.writeStringField(StructureUtils.CONCEPT_IDENTITY, referenceResolver.resolve(ref).getUrn()); + } + final Representation localRepresentation = component.getLocalRepresentation(); + if (localRepresentation != null) { + representationWriter.writeRepresentation(jsonGenerator, localRepresentation, StructureUtils.LOCAL_REPRESENTATION); + } + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ConceptRoleWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ConceptRoleWriter.java new file mode 100644 index 0000000..7610394 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ConceptRoleWriter.java @@ -0,0 +1,27 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.serializer.sdmx21.ReferenceResolver; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class ConceptRoleWriter { + + private final ReferenceResolver referenceResolver; + + public void write(JsonGenerator jsonGenerator, List conceptRoles) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.CONCEPT_ROLES); + jsonGenerator.writeStartArray(); + if (conceptRoles != null && !conceptRoles.isEmpty()) { + for (ArtefactReference conceptRef : conceptRoles) { + jsonGenerator.writeString(referenceResolver.resolve(conceptRef).getUrn()); + } + } + jsonGenerator.writeEndArray(); + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ConceptSchemeWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ConceptSchemeWriter.java new file mode 100644 index 0000000..cce56ad --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ConceptSchemeWriter.java @@ -0,0 +1,59 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Concept; +import com.epam.jsdmx.infomodel.sdmx30.ConceptScheme; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class ConceptSchemeWriter extends MaintainableWriter { + + private final NameableWriter nameableWriter; + private final RepresentationWriter representationWriter; + + public ConceptSchemeWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + NameableWriter nameableWriter, + RepresentationWriter representationWriter) { + super(versionableWriter, linksWriter); + this.nameableWriter = nameableWriter; + this.representationWriter = representationWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, ConceptScheme conceptScheme) throws IOException { + super.writeFields(jsonGenerator, conceptScheme); + List conceptSchemeItems = conceptScheme.getItems(); + if (conceptSchemeItems != null) { + jsonGenerator.writeFieldName(StructureUtils.CONCEPTS); + jsonGenerator.writeStartArray(); + if (!conceptSchemeItems.isEmpty()) { + for (Concept concept : conceptSchemeItems) { + jsonGenerator.writeStartObject(); + nameableWriter.write(jsonGenerator, concept); + + representationWriter.writeRepresentation(jsonGenerator, concept.getCoreRepresentation(), StructureUtils.CORE_REPRESENTATION); + + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + jsonGenerator.writeBooleanField(StructureUtils.IS_PARTIAL, conceptScheme.isPartial()); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getConceptSchemes(); + } + + @Override + protected String getArrayName() { + return StructureUtils.CONCEPT_SCHEMES; + } + +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ContactsWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ContactsWriter.java new file mode 100644 index 0000000..fd01a1d --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ContactsWriter.java @@ -0,0 +1,76 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.net.URI; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Contact; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections4.CollectionUtils; + +public class ContactsWriter { + + public void writeContacts(JsonGenerator jsonGenerator, List contacts) throws IOException { + if (CollectionUtils.isNotEmpty(contacts)) { + jsonGenerator.writeFieldName(StructureUtils.CONTACTS); + jsonGenerator.writeStartArray(); + for (Contact contact : contacts) { + if (contact != null) { + jsonGenerator.writeStartObject(); + + String name = contact.getName(); + if (name != null) { + jsonGenerator.writeStringField(StructureUtils.NAME, name); + } + + String organizationUnit = contact.getOrganizationUnit(); + writeOrganisationUnit(jsonGenerator, organizationUnit); + + InternationalString responsibility = contact.getResponsibility(); + StructureUtils.writeInternationalString(jsonGenerator, responsibility, StructureUtils.ROLE); + + String telephone = contact.getTelephone(); + writeOneStringArray(jsonGenerator, telephone, StructureUtils.TELEPHONES); + + String fax = contact.getFax(); + writeOneStringArray(jsonGenerator, fax, StructureUtils.FAXES); + + String x400 = contact.getX400(); + writeOneStringArray(jsonGenerator, x400, StructureUtils.X_400_S); + + URI uri = contact.getUri(); + writeURI(jsonGenerator, uri); + + String email = contact.getEmail(); + writeOneStringArray(jsonGenerator, email, StructureUtils.EMAILS); + + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } + + private void writeOrganisationUnit(JsonGenerator jsonGenerator, String organizationUnit) throws IOException { + if (organizationUnit != null) { + jsonGenerator.writeStringField(StructureUtils.DEPARTMENT, organizationUnit); + } + } + + private void writeURI(JsonGenerator jsonGenerator, URI uri) throws IOException { + if (uri != null) { + writeOneStringArray(jsonGenerator, uri.toString(), StructureUtils.URIS); + } + } + + private void writeOneStringArray(JsonGenerator jsonGenerator, String parameter, String parameterName) throws IOException { + jsonGenerator.writeFieldName(parameterName); + jsonGenerator.writeStartArray(); + if (parameter != null) { + jsonGenerator.writeString(parameter); + } + jsonGenerator.writeEndArray(); + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ContentConstraintWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ContentConstraintWriter.java new file mode 100644 index 0000000..d2ff36a --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/ContentConstraintWriter.java @@ -0,0 +1,136 @@ +package com.epam.jsdmx.json10.structure.writer; + +import static com.epam.jsdmx.json10.structure.writer.StructureUtils.CONSTRAINT_ROLE_STRING; + +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Constraint; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.MetadataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendar; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections4.CollectionUtils; + +public class ContentConstraintWriter extends MaintainableWriter { + + private final ReferenceAdapter referenceAdapter; + private final DataKeySetsWriter dataKeySetsWriter; + private final CubeRegionWriter cubeRegionWriter; + private final MetadataConstraintWriter metadataConstraintWriter; + + public ContentConstraintWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + ReferenceAdapter referenceAdapter, + DataKeySetsWriter dataKeySetsWriter, + CubeRegionWriter cubeRegionWriter, + MetadataConstraintWriter metadataConstraintWriter) { + super(versionableWriter, linksWriter); + this.referenceAdapter = referenceAdapter; + this.dataKeySetsWriter = dataKeySetsWriter; + this.cubeRegionWriter = cubeRegionWriter; + this.metadataConstraintWriter = metadataConstraintWriter; + } + + @Override + protected void writeFields(JsonGenerator gen, Constraint constraint) throws IOException { + super.writeFields(gen, constraint); + writeConstrainedArtefacts(gen, constraint.getConstrainedArtefacts()); + if (constraint.getConstraintRoleType() != null) { + String constraintRoleType = CONSTRAINT_ROLE_STRING.get(constraint.getConstraintRoleType()); + gen.writeStringField(StructureUtils.ROLE, constraintRoleType); + } + + if (constraint instanceof DataConstraint) { + DataConstraint dataConstraint = (DataConstraint) constraint; + writeReleaseCalendar(gen, dataConstraint.getReleaseCalendar()); + if (CollectionUtils.isNotEmpty(dataConstraint.getCubeRegions())) { + cubeRegionWriter.write(gen, dataConstraint.getCubeRegions()); + } + if (CollectionUtils.isNotEmpty(dataConstraint.getDataContentKeys())) { + dataKeySetsWriter.write(gen, dataConstraint.getDataContentKeys()); + } + } else { + MetadataConstraint metadataConstraint = (MetadataConstraint) constraint; + writeReleaseCalendar(gen, metadataConstraint.getReleaseCalendar()); + metadataConstraintWriter.writeMetadataTargetRegions(gen, metadataConstraint.getMetadataTargetRegions()); + } + } + + private void writeConstrainedArtefacts(JsonGenerator gen, List constrainedArtefacts) throws IOException { + if (CollectionUtils.isNotEmpty(constrainedArtefacts)) { + gen.writeFieldName(StructureUtils.CONSTRAINT_ATTACHMENT); + gen.writeStartObject(); + List providerRef = StructureUtils.getArtefactReferencesByStructureClass(constrainedArtefacts, StructureClassImpl.DATA_PROVIDER); + if (providerRef.size() != 0) { + gen.writeStringField(StructureUtils.DATA_PROVIDER, referenceAdapter.toAdaptedUrn(providerRef.get(0))); + } + + List dataStructures = StructureUtils.getArtefactReferencesByStructureClass( + constrainedArtefacts, + StructureClassImpl.DATA_STRUCTURE + ); + StructureUtils.writeArtefactReferences(gen, dataStructures, StructureUtils.DATA_STRUCTURES, referenceAdapter); + List dataFlows = StructureUtils.getArtefactReferencesByStructureClass(constrainedArtefacts, StructureClassImpl.DATAFLOW); + StructureUtils.writeArtefactReferences(gen, dataFlows, StructureUtils.DATAFLOWS, referenceAdapter); + + List metadataStructures = StructureUtils.getArtefactReferencesByStructureClass( + constrainedArtefacts, + StructureClassImpl.METADATA_STRUCTURE + ); + StructureUtils.writeArtefactReferences(gen, metadataStructures, StructureUtils.METADATA_STRUCTURES, referenceAdapter); + List metadataFlows = StructureUtils.getArtefactReferencesByStructureClass(constrainedArtefacts, StructureClassImpl.METADATAFLOW); + StructureUtils.writeArtefactReferences(gen, metadataFlows, StructureUtils.METADATAFLOWS, referenceAdapter); + List metadataSets = StructureUtils.getArtefactReferencesByStructureClass(constrainedArtefacts, StructureClassImpl.METADATA_SET); + StructureUtils.writeArtefactReferences(gen, metadataSets, StructureUtils.METADATA_SETS, referenceAdapter); + + List provisionAgreements = StructureUtils.getArtefactReferencesByStructureClass( + constrainedArtefacts, + StructureClassImpl.PROVISION_AGREEMENT + ); + StructureUtils.writeArtefactReferences(gen, provisionAgreements, StructureUtils.PROVISION_AGREEMENTS, referenceAdapter); + gen.writeEndObject(); + } + } + + private void writeReleaseCalendar(JsonGenerator gen, ReleaseCalendar releaseCalendar) throws IOException { + if (releaseCalendar != null) { + gen.writeFieldName(StructureUtils.RELEASE_CALENDAR); + gen.writeStartObject(); + String tolerance = releaseCalendar.getTolerance(); + if (tolerance != null) { + gen.writeStringField(StructureUtils.TOLERANCE, tolerance); + } + String offset = releaseCalendar.getOffset(); + if (offset != null) { + gen.writeStringField(StructureUtils.OFFSET, offset); + } + String periodicity = releaseCalendar.getPeriodicity(); + if (periodicity != null) { + gen.writeStringField(StructureUtils.PERIODICITY, periodicity); + } + gen.writeEndObject(); + } + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + var constraints = new HashSet(); + constraints.addAll(artefacts.getDataConstraints()); + constraints.addAll(artefacts.getMetadataConstraints()); + return constraints; + } + + @Override + protected String getArrayName() { + return StructureUtils.CONTENT_CONSTRAINT; + } + +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CubeRegionWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CubeRegionWriter.java new file mode 100644 index 0000000..4f316ea --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/CubeRegionWriter.java @@ -0,0 +1,69 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.CubeRegion; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionKey; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections4.CollectionUtils; + +public class CubeRegionWriter { + private final SelectionValueWriter selectionValueWriter; + private final AnnotableWriter annotableWriter; + + public CubeRegionWriter(SelectionValueWriter selectionValueWriter, AnnotableWriter annotableWriter) { + this.selectionValueWriter = selectionValueWriter; + this.annotableWriter = annotableWriter; + } + + public void write(JsonGenerator generator, List cubeRegions) throws IOException { + generator.writeFieldName(StructureUtils.CUBE_REGIONS); + generator.writeStartArray(); + if (CollectionUtils.isNotEmpty(cubeRegions)) { + for (CubeRegion cubeRegion : cubeRegions) { + generator.writeStartObject(); + generator.writeBooleanField(StructureUtils.IS_INCLUDED, cubeRegion.isIncluded()); + writeAttributes(generator, cubeRegion.getMemberSelections()); + writeKeyValues(generator, cubeRegion.getCubeRegionKeys()); + annotableWriter.write(generator, cubeRegion); + generator.writeEndObject(); + } + } + generator.writeEndArray(); + } + + private void writeAttributes(JsonGenerator generator, List memberSelections) throws IOException { + if (CollectionUtils.isNotEmpty(memberSelections)) { + generator.writeFieldName(StructureUtils.ATTRIBUTES); + generator.writeStartArray(); + for (MemberSelection memberSelection : memberSelections) { + if (memberSelection != null) { + generator.writeStartObject(); + + generator.writeStringField(StructureUtils.ID, memberSelection.getComponentId()); + selectionValueWriter.writeSelectionValues(generator, memberSelection.getSelectionValues()); + + generator.writeEndObject(); + } + } + generator.writeEndArray(); + } + } + + private void writeKeyValues(JsonGenerator jsonGenerator, List cubeRegionKeys) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.KEY_VALUES); + jsonGenerator.writeStartArray(); + if (CollectionUtils.isNotEmpty(cubeRegionKeys)) { + for (CubeRegionKey cubeRegionKey : cubeRegionKeys) { + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField(StructureUtils.ID, cubeRegionKey.getComponentId()); + selectionValueWriter.writeSelectionValues(jsonGenerator, cubeRegionKey.getSelectionValues()); + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataKeySetsWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataKeySetsWriter.java new file mode 100644 index 0000000..473442a --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataKeySetsWriter.java @@ -0,0 +1,67 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.ComponentValue; +import com.epam.jsdmx.infomodel.sdmx30.DataKey; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySet; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections4.CollectionUtils; + +public class DataKeySetsWriter { + + public void write(JsonGenerator generator, List dataKeySets) throws IOException { + if (CollectionUtils.isNotEmpty(dataKeySets)) { + generator.writeFieldName(StructureUtils.DATA_KEY_SETS); + generator.writeStartArray(); + for (DataKeySet dataKeySet : dataKeySets) { + if (dataKeySet != null) { + generator.writeStartObject(); + + generator.writeBooleanField(StructureUtils.IS_INCLUDED, dataKeySet.isIncluded()); + + writeDataKeys(generator, dataKeySet.getKeys()); + + generator.writeEndObject(); + } + } + generator.writeEndArray(); + } + } + + + private void writeDataKeys(JsonGenerator jsonGenerator, List keys) throws IOException { + if (CollectionUtils.isNotEmpty(keys)) { + jsonGenerator.writeFieldName(StructureUtils.KEYS); + jsonGenerator.writeStartArray(); + for (DataKey dataKey : keys) { + if (dataKey != null) { + jsonGenerator.writeStartObject(); + writeKeyValues(jsonGenerator, dataKey.getKeyValues()); + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } + + private void writeKeyValues(JsonGenerator jsonGenerator, List keyValues) throws IOException { + if (CollectionUtils.isNotEmpty(keyValues)) { + jsonGenerator.writeFieldName(StructureUtils.KEY_VALUES); + jsonGenerator.writeStartArray(); + for (ComponentValue componentValue : keyValues) { + if (componentValue != null) { + jsonGenerator.writeStartObject(); + + jsonGenerator.writeStringField(StructureUtils.ID, componentValue.getComponentId()); + jsonGenerator.writeStringField(StructureUtils.VALUE, componentValue.getValue()); + + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataStructureComponentsUtils.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataStructureComponentsUtils.java new file mode 100644 index 0000000..7740907 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataStructureComponentsUtils.java @@ -0,0 +1,34 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import com.epam.jsdmx.infomodel.sdmx30.Component; +import com.epam.jsdmx.infomodel.sdmx30.ComponentList; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public final class DataStructureComponentsUtils { + + public static boolean isEmpty(ComponentList componentList) { + if (componentList == null) { + return true; + } + + List components = Optional.of(componentList) + .map(ComponentList::getComponents) + .orElse(Collections.emptyList()); + return components.isEmpty(); + } + + public static boolean areAllEmpty(ComponentList... componentLists) { + for (ComponentList componentList : componentLists) { + if (!isEmpty(componentList)) { + return false; + } + } + return true; + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataStructureDefinitionWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataStructureDefinitionWriter.java new file mode 100644 index 0000000..0140cf4 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataStructureDefinitionWriter.java @@ -0,0 +1,86 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinition; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.GroupDimensionDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptor; +import com.epam.jsdmx.serializer.common.TimeDimensionLocalRepresentationAdapter; +import com.epam.jsdmx.serializer.sdmx21.DataStructure30To21ComponentAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; + + +public class DataStructureDefinitionWriter extends MaintainableWriter { + + private final AttributeListWriter attributeListWriterJson; + private final DimensionListWriter dimensionListWriterJson; + private final GroupDimensionListWriter groupDimensionListWriter; + private final MeasureListWriter measureListWriterJson; + private final DataStructure30To21ComponentAdapter dsdComponentAdapter; + private final TimeDimensionLocalRepresentationAdapter timeDimensionLocalRepresentationAdapter; + + + public DataStructureDefinitionWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + AttributeListWriter attributeListWriterJson, + DimensionListWriter dimensionListWriterJson, + MeasureListWriter measureListWriterJson, + GroupDimensionListWriter groupDimensionListWriter, + DataStructure30To21ComponentAdapter dsdComponentAdapter, + TimeDimensionLocalRepresentationAdapter timeDimensionLocalRepresentationAdapter) { + super(versionableWriter, linksWriter); + this.attributeListWriterJson = attributeListWriterJson; + this.dimensionListWriterJson = dimensionListWriterJson; + this.measureListWriterJson = measureListWriterJson; + this.groupDimensionListWriter = groupDimensionListWriter; + this.dsdComponentAdapter = dsdComponentAdapter; + this.timeDimensionLocalRepresentationAdapter = timeDimensionLocalRepresentationAdapter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, DataStructureDefinition dsd) throws IOException { + super.writeFields(jsonGenerator, dsd); + writeDataStructureComponents(jsonGenerator, dsd); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getDataStructures(); + } + + @Override + protected String getArrayName() { + return StructureUtils.DATA_STRUCTURES; + } + + private void writeDataStructureComponents(JsonGenerator jsonGenerator, DataStructureDefinition dsd) throws IOException { + dsd = timeDimensionLocalRepresentationAdapter.adapt(dsd); + dsd = dsdComponentAdapter.recompose(dsd); + jsonGenerator.writeFieldName(StructureUtils.DATA_STRUCTURE_COMPONENTS); + AttributeDescriptor attributeDescriptor = dsd.getAttributeDescriptor(); + DimensionDescriptor dimensionDescriptor = dsd.getDimensionDescriptor(); + MeasureDescriptor measureDescriptor = dsd.getMeasureDescriptor(); + List groupDimensionDescriptors = dsd.getGroupDimensionDescriptors(); + if (DataStructureComponentsUtils.areAllEmpty( + attributeDescriptor, + dimensionDescriptor, + measureDescriptor + )) { + jsonGenerator.writeNull(); + } else { + jsonGenerator.writeStartObject(); + measureListWriterJson.write(jsonGenerator, measureDescriptor); + dimensionListWriterJson.write(jsonGenerator, dimensionDescriptor); + groupDimensionListWriter.write(jsonGenerator, groupDimensionDescriptors); + attributeListWriterJson.write(jsonGenerator, attributeDescriptor); + jsonGenerator.writeEndObject(); + } + } + +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataflowWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataflowWriter.java new file mode 100644 index 0000000..a2f5fc4 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DataflowWriter.java @@ -0,0 +1,41 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Dataflow; +import com.epam.jsdmx.serializer.sdmx21.ReferenceResolver; + +import com.fasterxml.jackson.core.JsonGenerator; + + +public class DataflowWriter extends MaintainableWriter { + + private final ReferenceResolver referenceResolver; + + public DataflowWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + ReferenceResolver referenceResolver) { + super(versionableWriter, linksWriter); + this.referenceResolver = referenceResolver; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, Dataflow dataflow) throws IOException { + super.writeFields(jsonGenerator, dataflow); + if (dataflow.getStructure() != null) { + jsonGenerator.writeStringField(StructureUtils.STRUCTURE, referenceResolver.resolve(dataflow.getStructure()).getUrn()); + } + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getDataflows(); + } + + @Override + protected String getArrayName() { + return StructureUtils.DATAFLOWS; + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DefaultHeaderProvider.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DefaultHeaderProvider.java new file mode 100644 index 0000000..8046754 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DefaultHeaderProvider.java @@ -0,0 +1,44 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.net.URI; +import java.time.Instant; +import java.util.List; +import java.util.Locale; + +import com.epam.jsdmx.infomodel.sdmx30.DefaultLocaleHolder; +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.serializer.sdmx30.common.Header; + +import lombok.SneakyThrows; +import org.apache.commons.lang3.RandomUtils; + +public class DefaultHeaderProvider { + public static final String SCHEMA + = "https://github.com/sdmx-twg/sdmx-json/blob/v1.0/structure-message/tools/schemas/1.0/sdmx-json-structure-schema.json"; + + @SneakyThrows + public Header provide() { + Header header = new Header(); + header.setSchema(new URI(SCHEMA)); + header.setId(generateId()); + header.setContentLanguages(getDefaultLocales()); + header.setTest(false); + header.setPrepared(Instant.now()); + header.setSender(generateUnknownParty()); + return header; + } + + private String generateId() { + return "IDREF" + RandomUtils.nextInt(1000, 9999); + } + + private Party generateUnknownParty() { + return Party.builder() + .id("unknown") + .build(); + } + + private List getDefaultLocales() { + return List.of(DefaultLocaleHolder.INSTANCE.get()); + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DimensionListWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DimensionListWriter.java new file mode 100644 index 0000000..44a8af8 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/DimensionListWriter.java @@ -0,0 +1,95 @@ +package com.epam.jsdmx.json10.structure.writer; + + +import java.io.IOException; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.Dimension; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponent; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.TimeDimension; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = false) +public class DimensionListWriter { + + private final IdentifiableWriter identifiableWriter; + private final ConceptRoleWriter conceptRoleWriter; + private final ComponentWriter componentWriter; + + public DimensionListWriter(IdentifiableWriter identifiableWriter, ConceptRoleWriter conceptRoleWriter, ComponentWriter componentWriter) { + this.identifiableWriter = identifiableWriter; + this.conceptRoleWriter = conceptRoleWriter; + this.componentWriter = componentWriter; + } + + public void write(JsonGenerator jsonGenerator, DimensionDescriptor descriptor) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.DIMENSION_LIST); + + if (descriptor == null) { + jsonGenerator.writeNull(); + return; + } + + var descriptorImpl = (DimensionDescriptorImpl) descriptor; + descriptorImpl.setId(StructureUtils.DIMENSION_DESCRIPTOR_ID); + + jsonGenerator.writeStartObject(); + + identifiableWriter.write(jsonGenerator, descriptorImpl); + List components = descriptorImpl.getComponents(); + writeDimensions(jsonGenerator, components); + writeTimeDimensions(jsonGenerator, components); + + jsonGenerator.writeEndObject(); + } + + private void writeDimensions(JsonGenerator jsonGenerator, List components) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.DIMENSIONS); + jsonGenerator.writeStartArray(); + List dimensions = Optional.ofNullable(components) + .stream() + .flatMap(List::stream) + .filter(d -> Dimension.class.isAssignableFrom(d.getClass())) + .map(Dimension.class::cast) + .collect(Collectors.toList()); + if (!dimensions.isEmpty()) { + for (Dimension dimension : dimensions) { + jsonGenerator.writeStartObject(); + componentWriter.write(jsonGenerator, dimension); + jsonGenerator.writeNumberField(StructureUtils.POSITION, dimension.getOrder()); + jsonGenerator.writeStringField(StructureUtils.TYPE, "Dimension"); + conceptRoleWriter.write(jsonGenerator, dimension.getConceptRoles()); + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + + private void writeTimeDimensions(JsonGenerator jsonGenerator, List components) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.TIME_DIMENSIONS); + jsonGenerator.writeStartArray(); + List timeDimensions = Optional.ofNullable(components) + .stream() + .flatMap(List::stream) + .filter(d -> d instanceof TimeDimension) + .map(TimeDimension.class::cast) + .collect(Collectors.toList()); + if (!timeDimensions.isEmpty()) { + for (TimeDimension dimension : timeDimensions) { + jsonGenerator.writeStartObject(); + componentWriter.write(jsonGenerator, dimension); + jsonGenerator.writeNumberField(StructureUtils.POSITION, dimension.getOrder()); + jsonGenerator.writeStringField(StructureUtils.TYPE, "TimeDimension"); + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/GroupDimensionListWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/GroupDimensionListWriter.java new file mode 100644 index 0000000..50699b1 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/GroupDimensionListWriter.java @@ -0,0 +1,40 @@ +package com.epam.jsdmx.json10.structure.writer; + + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.GroupDimensionDescriptor; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections4.CollectionUtils; + +public class GroupDimensionListWriter { + + private final IdentifiableWriter identifiableWriter; + + public GroupDimensionListWriter(IdentifiableWriter identifiableWriter) { + this.identifiableWriter = identifiableWriter; + } + + public void write(JsonGenerator jsonGenerator, List descriptors) throws IOException { + if (CollectionUtils.isEmpty(descriptors)) { + return; + } + + jsonGenerator.writeArrayFieldStart(StructureUtils.GROUPS); + + for (GroupDimensionDescriptor descriptor : descriptors) { + jsonGenerator.writeStartObject(); + identifiableWriter.write(jsonGenerator, descriptor); + + jsonGenerator.writeFieldName(StructureUtils.GROUP_DIMENSIONS); + String[] dimensionsStringList = descriptor.getDimensions().toArray(new String[0]); + jsonGenerator.writeArray(dimensionsStringList, 0, dimensionsStringList.length); + + jsonGenerator.writeEndObject(); + } + + jsonGenerator.writeEndArray(); + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/HierarchicalCodelistWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/HierarchicalCodelistWriter.java new file mode 100644 index 0000000..e102743 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/HierarchicalCodelistWriter.java @@ -0,0 +1,128 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CodingFormat; +import com.epam.jsdmx.infomodel.sdmx30.Facet; +import com.epam.jsdmx.infomodel.sdmx30.HierarchicalCode; +import com.epam.jsdmx.infomodel.sdmx30.Hierarchy; +import com.epam.jsdmx.infomodel.sdmx30.Level; +import com.epam.jsdmx.infomodel.sdmx30.TextFormatImpl; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; +import com.epam.jsdmx.serializer.sdmx21.ReferenceResolver; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections4.CollectionUtils; + +public class HierarchicalCodelistWriter extends MaintainableWriter { + + private final IdentifiableWriter identifiableWriter; + private final NameableWriter nameableWriter; + private final ReferenceResolver referenceResolver; + private final ReferenceAdapter referenceAdapter; + + public HierarchicalCodelistWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + IdentifiableWriter identifiableWriter, + NameableWriter nameableWriter, + ReferenceResolver referenceResolver, + ReferenceAdapter referenceAdapter) { + super(versionableWriter, linksWriter); + this.identifiableWriter = identifiableWriter; + this.nameableWriter = nameableWriter; + this.referenceResolver = referenceResolver; + this.referenceAdapter = referenceAdapter; + } + + @Override + protected void writeFields(JsonGenerator gen, Hierarchy hierarchy) throws IOException { + super.writeFields(gen, hierarchy); + if (CollectionUtils.isNotEmpty(hierarchy.getCodes())) { + gen.writeFieldName(StructureUtils.HIERARCHIES); + gen.writeStartArray(); + writeHierarchies(gen, hierarchy.getCodes()); + gen.writeEndArray(); + } + writeHierarchyLevel(gen, hierarchy.getLevel()); + } + + private void writeHierarchies(JsonGenerator gen, List codes) throws IOException { + // write single hierarchy + gen.writeStartObject(); + gen.writeStringField(StructureUtils.ID, "Hierarchy"); + gen.writeStringField(StructureUtils.NAME, "Hierarchy"); + gen.writeFieldName(StructureUtils.HIERARCHICAL_CODES); + gen.writeStartArray(); + writeHierarchicalCodes(gen, codes); + gen.writeEndArray(); + gen.writeEndObject(); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getHierarchies(); + } + + @Override + protected String getArrayName() { + return StructureUtils.HIERARCHICAL_CODELISTS; + } + + private void writeHierarchyLevel(JsonGenerator gen, Level level) throws IOException { + if (level != null) { + gen.writeFieldName(StructureUtils.LEVEL); + gen.writeStartObject(); + nameableWriter.write(gen, level); + writeCodingFormat(gen, level); + writeHierarchyLevel(gen, level.getChild()); + gen.writeEndObject(); + } + + } + + private void writeCodingFormat(JsonGenerator gen, Level level) throws IOException { + List levelCodeFormat = level.getCodeFormat(); + if (levelCodeFormat != null) { + gen.writeFieldName(StructureUtils.CODING_FORMAT); + gen.writeStartObject(); + for (CodingFormat codingFormat : levelCodeFormat) { + if (codingFormat != null) { + Facet format = codingFormat.getCodingFormat(); + TextFormatImpl textFormat = new TextFormatImpl(Set.of(format)); + StructureUtils.writeCommonFormatAttributes(gen, textFormat); + } + } + gen.writeEndObject(); + } + } + + private void writeHierarchicalCodes(JsonGenerator gen, List codes) throws IOException { + if (codes != null) { + if (!codes.isEmpty()) { + for (HierarchicalCode code : codes) { + gen.writeStartObject(); + identifiableWriter.write(gen, code); + gen.writeStringField(StructureUtils.VALID_FROM, StructureUtils.mapInstantToString(code.getValidFrom())); + gen.writeStringField(StructureUtils.VALID_TO, StructureUtils.mapInstantToString(code.getValidTo())); + if (code.getCode() != null) { + final ArtefactReference resolvedCodeRef = referenceResolver.resolve(code.getCode()); + gen.writeStringField(StructureUtils.CODE, referenceAdapter.toAdaptedUrn(resolvedCodeRef)); + gen.writeStringField(StructureUtils.CODE_ID, code.getCode().getItemId()); + } + gen.writeStringField(StructureUtils.LEVEL, code.getLevelId()); + if (code.getHierarchicalCodes() != null && !code.getHierarchicalCodes().isEmpty()) { + gen.writeFieldName(StructureUtils.HIERARCHICAL_CODES); + gen.writeStartArray(); + writeHierarchicalCodes(gen, code.getHierarchicalCodes()); + gen.writeEndArray(); + } + gen.writeEndObject(); + } + } + } + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/IdentifiableWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/IdentifiableWriter.java new file mode 100644 index 0000000..37fb622 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/IdentifiableWriter.java @@ -0,0 +1,26 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefact; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.Data; + +@Data +public class IdentifiableWriter { + + private AnnotableWriter annotableWriter; + + public IdentifiableWriter(AnnotableWriter annotableWriter) { + this.annotableWriter = annotableWriter; + } + + public void write(JsonGenerator jsonGenerator, T artefact) throws IOException { + annotableWriter.write(jsonGenerator, artefact); + String id = artefact.getId(); + if (id != null) { + jsonGenerator.writeStringField(StructureUtils.ID, id); + } + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/Json10StructureWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/Json10StructureWriter.java new file mode 100644 index 0000000..be8f298 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/Json10StructureWriter.java @@ -0,0 +1,88 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.serializer.sdmx30.structure.StructureWriter; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class Json10StructureWriter extends BaseWriterJson implements StructureWriter { + + protected final MetaWriter metaWriter; + protected final List> writers; + + public Json10StructureWriter(ObjectMapper mapper, + OutputStream outputStream, + MetaWriter metaWriter, + List> writers) { + super(mapper, outputStream); + this.metaWriter = metaWriter; + this.writers = writers; + } + + @Override + public void write(Artefacts artefacts) { + try { + if (artefacts != null) { + jsonGenerator.writeStartObject(); + jsonGenerator.writeFieldName(StructureUtils.DATA); + + jsonGenerator.writeStartObject(); + writeArtefacts(artefacts); + jsonGenerator.writeEndObject(); + + metaWriter.writeDefaultHeader(jsonGenerator); + + jsonGenerator.writeEndObject(); + + jsonGenerator.flush(); + jsonGenerator.close(); + } + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + protected void writeArtefacts(Artefacts artefacts) throws IOException { + + writers.forEach(writer -> { + Set maintainableArtefacts = writer.extractArtefacts(artefacts); + try { + if (!maintainableArtefacts.isEmpty()) { + jsonGenerator.writeFieldName(writer.getArrayName()); + jsonGenerator.writeStartArray(); + maintainableArtefacts.forEach(art -> { + try { + if (art.getVersion().isStable()) { + writer.write(jsonGenerator, art); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + jsonGenerator.writeEndArray(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + + protected void writeArtefact(MaintainableWriter writer, + Set artefacts, + String artefactName) throws IOException { + if (artefacts != null && !artefacts.isEmpty()) { + jsonGenerator.writeFieldName(artefactName); + jsonGenerator.writeStartArray(); + for (T artefact : artefacts) { + writer.write(jsonGenerator, artefact); + } + jsonGenerator.writeEndArray(); + } + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/Json10WriterFactory.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/Json10WriterFactory.java new file mode 100644 index 0000000..fb71635 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/Json10WriterFactory.java @@ -0,0 +1,136 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; +import com.epam.jsdmx.serializer.common.TimeDimensionLocalRepresentationAdapter; +import com.epam.jsdmx.serializer.sdmx21.DataStructure30To21ComponentAdapter; +import com.epam.jsdmx.serializer.sdmx21.ReferenceResolver; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultReferenceAdapter; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class Json10WriterFactory { + + private final ObjectMapper mapper; + private final List languagePriorities; + private final DefaultHeaderProvider defaultHeaderProvider; + private final DataStructure30To21ComponentAdapter dsdComponentAdapter; + private final ReferenceResolver referenceResolver; + private final ReferenceAdapter referenceAdapter; + private final TimeDimensionLocalRepresentationAdapter timeDimensionLocalRepresentationAdapter; + + public Json10WriterFactory(ObjectMapper mapper, + DataStructure30To21ComponentAdapter dsdComponentAdapter, + TimeDimensionLocalRepresentationAdapter timeDimensionLocalRepresentationAdapter, + ReferenceResolver referenceResolver, + List languagePriorities, + DefaultHeaderProvider defaultHeaderProvider, + ReferenceAdapter referenceAdapter) { + this.mapper = mapper; + this.languagePriorities = languagePriorities; + this.defaultHeaderProvider = defaultHeaderProvider; + this.dsdComponentAdapter = dsdComponentAdapter; + this.referenceResolver = referenceResolver; + this.referenceAdapter = referenceAdapter; + this.timeDimensionLocalRepresentationAdapter = timeDimensionLocalRepresentationAdapter; + } + + public Json10WriterFactory(ObjectMapper mapper, + DataStructure30To21ComponentAdapter dsdComponentAdapter, + TimeDimensionLocalRepresentationAdapter timeDimensionLocalRepresentationAdapter, + ReferenceResolver referenceResolver, + List languagePriorities, + DefaultHeaderProvider defaultHeaderProvider) { + this( + mapper, + dsdComponentAdapter, + timeDimensionLocalRepresentationAdapter, + referenceResolver, + languagePriorities, + defaultHeaderProvider, + new DefaultReferenceAdapter() + ); + } + + + public Json10StructureWriter newInstance(OutputStream writeTo) { + return new Json10StructureWriter( + mapper, + writeTo, + new MetaWriter(languagePriorities, defaultHeaderProvider), + writers() + ); + } + + public Json10StructureWriter newInstance(OutputStream writeTo, + Map> customStructureWriters) { + var defaultStructureWriters = writers(); + List> structureWriters = new ArrayList<>(); + for (var writer : defaultStructureWriters) { + writer.getWritableArtefactStructureClass() + .filter(customStructureWriters::containsKey) + .map(customStructureWriters::get) + .ifPresentOrElse(structureWriters::add, () -> structureWriters.add(writer)); + } + return new Json10StructureWriter( + mapper, + writeTo, + new MetaWriter(languagePriorities, defaultHeaderProvider), + structureWriters + ); + } + + private List> writers() { + final LinksWriter linksWriter = new LinksWriter(referenceAdapter); + final AnnotableWriter annotableWriter = new AnnotableWriter(linksWriter); + final IdentifiableWriter identifiableWriter = new IdentifiableWriter(annotableWriter); + final NameableWriter nameableWriter = new NameableWriter(identifiableWriter); + final VersionableWriter versionableWriter = new VersionableWriter(nameableWriter); + + final ContactsWriter contactsWriter = new ContactsWriter(); + final OrganisationWriter organisationWriter = new OrganisationWriter(contactsWriter, nameableWriter); + + final RepresentationWriter representationWriter = new RepresentationWriter(referenceResolver, referenceAdapter); + + final CodeWriterImpl codeImplWriter = new CodeWriterImpl(); + + final ConceptRoleWriter conceptRoleWriter = new ConceptRoleWriter(referenceResolver); + final ComponentWriter componentWriter = new ComponentWriter(identifiableWriter, representationWriter, referenceResolver); + final AttributeListWriter attributeListWriter = new AttributeListWriter(identifiableWriter, conceptRoleWriter, componentWriter); + final DimensionListWriter dimensionListWriter = new DimensionListWriter(identifiableWriter, conceptRoleWriter, componentWriter); + final MeasureListWriter measureListWriter = new MeasureListWriter(identifiableWriter, conceptRoleWriter, componentWriter); + final GroupDimensionListWriter groupDimensionListWriter = new GroupDimensionListWriter(identifiableWriter); + final DataKeySetsWriter dataKeySetsWriter = new DataKeySetsWriter(); + final CubeRegionWriter cubeRegionWriter = new CubeRegionWriter(new SelectionValueWriter(), annotableWriter); + final MetadataConstraintWriter metadataConstraintWriter = new MetadataConstraintWriter(new SelectionValueWriter()); + + return List.of( + new AgencySchemeWriter(versionableWriter, linksWriter, organisationWriter), + new CategorisationWriter(versionableWriter, linksWriter, referenceResolver, referenceAdapter), + new CategorySchemeWriter(versionableWriter, linksWriter, nameableWriter), + new CodelistWriter(versionableWriter, linksWriter, codeImplWriter, nameableWriter), + new ConceptSchemeWriter(versionableWriter, linksWriter, nameableWriter, representationWriter), + new DataStructureDefinitionWriter( + versionableWriter, + linksWriter, + attributeListWriter, + dimensionListWriter, + measureListWriter, + groupDimensionListWriter, + dsdComponentAdapter, + timeDimensionLocalRepresentationAdapter + ), + new DataflowWriter(versionableWriter, linksWriter, referenceResolver), + new HierarchicalCodelistWriter(versionableWriter, linksWriter, identifiableWriter, nameableWriter, referenceResolver, referenceAdapter), + new ContentConstraintWriter(versionableWriter, linksWriter, referenceAdapter, dataKeySetsWriter, cubeRegionWriter, metadataConstraintWriter) + ); + } + +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/JsonRuntimeException.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/JsonRuntimeException.java new file mode 100644 index 0000000..704f4d8 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/JsonRuntimeException.java @@ -0,0 +1,8 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; + +public class JsonRuntimeException extends RuntimeException { + public JsonRuntimeException(IOException e) { + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/LinksWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/LinksWriter.java new file mode 100644 index 0000000..28db649 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/LinksWriter.java @@ -0,0 +1,49 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalUri; +import com.epam.jsdmx.infomodel.sdmx30.Link; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class LinksWriter { + + private final ReferenceAdapter referenceAdapter; + + public LinksWriter(ReferenceAdapter referenceAdapter) { + this.referenceAdapter = referenceAdapter; + } + + public void writeLinks(JsonGenerator jsonGenerator, List links) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.LINKS); + jsonGenerator.writeStartArray(); + if (links != null && !links.isEmpty()) { + for (Link link : links) { + writeLink(jsonGenerator, link); + } + } + jsonGenerator.writeEndArray(); + } + + public void writeLinks(JsonGenerator jsonGenerator, InternationalUri uri) throws IOException { + if (uri != null) { + jsonGenerator.writeFieldName(StructureUtils.LINKS); + jsonGenerator.writeStartArray(); + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField(StructureUtils.URI, uri.getForDefaultLocale().toString()); + jsonGenerator.writeEndObject(); + jsonGenerator.writeEndArray(); + } + } + + private void writeLink(JsonGenerator jsonGenerator, Link link) throws IOException { + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField(StructureUtils.URN, referenceAdapter.adaptUrn(link.getUrn())); + jsonGenerator.writeStringField(StructureUtils.TYPE, referenceAdapter.adaptType(link.getType())); + jsonGenerator.writeStringField(StructureUtils.REL, link.getRel()); + jsonGenerator.writeEndObject(); + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MaintainableWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MaintainableWriter.java new file mode 100644 index 0000000..2682685 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MaintainableWriter.java @@ -0,0 +1,60 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RequiredArgsConstructor +public abstract class MaintainableWriter { + + private final VersionableWriter versionableWriter; + private final LinksWriter linksWriter; + + public void write(JsonGenerator jsonGenerator, MaintainableArtefact artefact) throws IOException { + T artefactCasted = (T) artefact; + jsonGenerator.writeStartObject(); + writeFields(jsonGenerator, artefactCasted); + jsonGenerator.writeEndObject(); + } + + protected void writeFields(JsonGenerator jsonGenerator, T artefact) throws IOException { + linksWriter.writeLinks(jsonGenerator, artefact.getLinks()); + versionableWriter.write(jsonGenerator, artefact); + jsonGenerator.writeBooleanField(StructureUtils.IS_FINAL, artefact.getVersion().isStable()); + jsonGenerator.writeStringField(StructureUtils.AGENCY_ID, artefact.getOrganizationId()); + } + + public void writeAndClose(JsonGenerator jsonGenerator, T maintainableArtefact) { + try (jsonGenerator) { + write(jsonGenerator, maintainableArtefact); + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + public Optional getWritableArtefactStructureClass() { + // if there is a need to find writer by its maintainable artefact type + return Optional.empty(); + } + + protected Set extractArtefacts(Artefacts artefacts) { + //different for writers with stream and the ones with dto + return Collections.emptySet(); + } + + protected String getArrayName() { + //different for writers with stream and the ones with dto + return null; + } + +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MeasureListWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MeasureListWriter.java new file mode 100644 index 0000000..57d441d --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MeasureListWriter.java @@ -0,0 +1,59 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Measure; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptorImpl; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.EqualsAndHashCode; +import org.apache.commons.collections4.CollectionUtils; + +@EqualsAndHashCode(callSuper = false) +public class MeasureListWriter { + + private final IdentifiableWriter identifiableWriter; + private final ConceptRoleWriter conceptRoleWriter; + private final ComponentWriter componentWriter; + + public MeasureListWriter(IdentifiableWriter identifiableWriter, ConceptRoleWriter conceptRoleWriter, ComponentWriter componentWriter) { + this.identifiableWriter = identifiableWriter; + this.conceptRoleWriter = conceptRoleWriter; + this.componentWriter = componentWriter; + } + + public void write(JsonGenerator jsonGenerator, MeasureDescriptor identifiableArtefact) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.MEASURE_LIST); + + if (identifiableArtefact == null) { + jsonGenerator.writeNull(); + return; + } + + // set fixed id + var measureDescriptor = (MeasureDescriptorImpl) identifiableArtefact; + measureDescriptor.setId(StructureUtils.MEASURE_DESCRIPTOR_ID); + + jsonGenerator.writeStartObject(); + + identifiableWriter.write(jsonGenerator, measureDescriptor); + writeMeasures(jsonGenerator, measureDescriptor.getComponents()); + + jsonGenerator.writeEndObject(); + } + + private void writeMeasures(JsonGenerator jsonGenerator, List components) throws IOException { + jsonGenerator.writeFieldName("primaryMeasure"); + + if (CollectionUtils.isNotEmpty(components)) { + jsonGenerator.writeStartObject(); + + final Measure primaryMeasure = components.get(0); + componentWriter.write(jsonGenerator, primaryMeasure); + + jsonGenerator.writeEndObject(); + } + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MetaWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MetaWriter.java new file mode 100644 index 0000000..488948b --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MetaWriter.java @@ -0,0 +1,66 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.util.List; +import java.util.Locale; +import java.util.Locale.LanguageRange; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.serializer.sdmx30.common.Header; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.SneakyThrows; + +public class MetaWriter { + + private final List languagePriorities; + private final DefaultHeaderProvider defaultHeaderProvider; + + public MetaWriter(List languagePriorities, DefaultHeaderProvider defaultHeaderProvider) { + this.languagePriorities = languagePriorities; + this.defaultHeaderProvider = defaultHeaderProvider; + } + + @SneakyThrows + public void writeHeader(JsonGenerator jsonGenerator, Header header) { + if (header == null) { + return; + } + jsonGenerator.writeFieldName(StructureUtils.META); + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField(StructureUtils.SCHEMA, header.getSchema().toString()); + jsonGenerator.writeStringField(StructureUtils.ID, header.getId()); + jsonGenerator.writeBooleanField(StructureUtils.TEST, header.isTest()); + jsonGenerator.writeStringField(StructureUtils.PREPARED, header.getPrepared().toString()); + jsonGenerator.writeArrayFieldStart(StructureUtils.CONTENT_LANGUAGES); + for (Locale locale : header.getContentLanguages()) { + jsonGenerator.writeString(locale.toString()); + } + jsonGenerator.writeEndArray(); + + final InternationalString name = header.getName(); + if (name != null) { + jsonGenerator.writeStringField(StructureUtils.NAME, name.getForRanges(languagePriorities)); + StructureUtils.writeInternationalString(jsonGenerator, name, StructureUtils.NAMES); + } + + writeParty(jsonGenerator, header.getSender()); + jsonGenerator.writeEndObject(); + } + + public void writeDefaultHeader(JsonGenerator jsonGenerator) { + Header header = defaultHeaderProvider.provide(); + writeHeader(jsonGenerator, header); + } + + @SneakyThrows + private void writeParty(JsonGenerator jsonGenerator, Party party) { + jsonGenerator.writeFieldName(StructureUtils.SENDER); + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField(StructureUtils.ID, party.getId()); + if (party.getName() != null) { + jsonGenerator.writeStringField(StructureUtils.NAME, party.getName().getForDefaultLocale()); + } + jsonGenerator.writeEndObject(); + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MetadataConstraintWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MetadataConstraintWriter.java new file mode 100644 index 0000000..4c54eb8 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/MetadataConstraintWriter.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.MetadataTargetRegion; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections4.CollectionUtils; + +public class MetadataConstraintWriter { + private final SelectionValueWriter selectionValueWriter; + + public MetadataConstraintWriter(SelectionValueWriter selectionValueWriter) { + this.selectionValueWriter = selectionValueWriter; + } + + public void writeMetadataTargetRegions(JsonGenerator gen, List metadataTargetRegions) throws IOException { + if (CollectionUtils.isNotEmpty(metadataTargetRegions)) { + gen.writeFieldName(StructureUtils.METADATA_TARGET_REGIONS); + gen.writeStartArray(); + for (MetadataTargetRegion metadataTargetRegion : metadataTargetRegions) { + if (metadataTargetRegion != null) { + gen.writeStartObject(); + gen.writeBooleanField(StructureUtils.INCLUDE, metadataTargetRegion.isIncluded()); + writeMemberSelections(gen, metadataTargetRegion.getMemberSelections()); + gen.writeEndObject(); + } + } + gen.writeEndArray(); + } + } + + private void writeMemberSelections(JsonGenerator generator, List memberSelections) throws IOException { + if (CollectionUtils.isNotEmpty(memberSelections)) { + generator.writeFieldName(StructureUtils.ATTRIBUTES); + generator.writeStartArray(); + for (MemberSelection memberSelection : memberSelections) { + if (memberSelection != null) { + generator.writeStartObject(); + + generator.writeStringField(StructureUtils.ID, memberSelection.getComponentId()); + selectionValueWriter.writeSelectionValues(generator, memberSelection.getSelectionValues()); + + generator.writeEndObject(); + } + } + generator.writeEndArray(); + } + } + +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/NameableWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/NameableWriter.java new file mode 100644 index 0000000..adf23df --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/NameableWriter.java @@ -0,0 +1,39 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Locale; + +import com.epam.jsdmx.infomodel.sdmx30.NameableArtefact; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class NameableWriter { + + private final IdentifiableWriter identifiableWriter; + private List languagePriorities; + + public NameableWriter(IdentifiableWriter identifiableWriter) { + this.identifiableWriter = identifiableWriter; + } + + public NameableWriter(IdentifiableWriter identifiableWriter, List languagePriorities) { + this.identifiableWriter = identifiableWriter; + this.languagePriorities = languagePriorities; + } + + public void write(JsonGenerator jsonGenerator, NameableArtefact artefact) throws IOException { + identifiableWriter.write(jsonGenerator, artefact); + if (artefact.getName() != null) { + jsonGenerator.writeStringField(StructureUtils.NAME, artefact.getName().getForRanges(languagePriorities)); + StructureUtils.writeInternationalString(jsonGenerator, artefact.getName(), StructureUtils.NAMES); + } + if (artefact.getDescription() != null && !artefact.getDescription().isEmpty()) { + jsonGenerator.writeStringField( + StructureUtils.DESCRIPTION, + artefact.getDescription().getForRanges(languagePriorities) + ); + StructureUtils.writeInternationalString(jsonGenerator, artefact.getDescription(), StructureUtils.DESCRIPTIONS); + } + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/OrganisationWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/OrganisationWriter.java new file mode 100644 index 0000000..13b7486 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/OrganisationWriter.java @@ -0,0 +1,57 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.epam.jsdmx.infomodel.sdmx30.Contact; +import com.epam.jsdmx.infomodel.sdmx30.Organisation; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; + +@AllArgsConstructor +public class OrganisationWriter { + + private final ContactsWriter contactsWriter; + private final NameableWriter nameableWriter; + + > void writeOrganisation(JsonGenerator jsonGenerator, List organisationItems, String organisationName) + throws IOException { + if (CollectionUtils.isNotEmpty(organisationItems)) { + Map parentIdWithHierarchy = new HashMap<>(); + for (T organisat : organisationItems) { + List> children = organisat.getHierarchy(); + if (CollectionUtils.isNotEmpty(children)) { + for (Organisation child : children) { + parentIdWithHierarchy.put(child.getId(), organisat.getId()); + } + } + } + + jsonGenerator.writeFieldName(organisationName); + jsonGenerator.writeStartArray(); + for (T organisation : organisationItems) { + writeOrganisation(jsonGenerator, parentIdWithHierarchy, organisation); + } + jsonGenerator.writeEndArray(); + } + } + + private > void writeOrganisation(JsonGenerator jsonGenerator, Map parentIdWithHierarchy, T organisation) + throws IOException { + if (organisation != null) { + jsonGenerator.writeStartObject(); + nameableWriter.write(jsonGenerator, organisation); + List contacts = organisation.getContacts(); + contactsWriter.writeContacts(jsonGenerator, contacts); + String id = organisation.getId(); + if (parentIdWithHierarchy.containsKey(id)) { + jsonGenerator.writeStringField(StructureUtils.PARENT, parentIdWithHierarchy.get(id)); + } + jsonGenerator.writeEndObject(); + } + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/RepresentationWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/RepresentationWriter.java new file mode 100644 index 0000000..bdc4c2f --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/RepresentationWriter.java @@ -0,0 +1,56 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.Optional; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Facet; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.infomodel.sdmx30.TextFormatImpl; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; +import com.epam.jsdmx.serializer.sdmx21.ReferenceResolver; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class RepresentationWriter { + + private final ReferenceResolver referenceResolver; + private final ReferenceAdapter referenceAdapter; + + public void writeRepresentation(JsonGenerator jsonGenerator, + Representation localRepresentation, + String representationName) throws IOException { + jsonGenerator.writeFieldName(representationName); + jsonGenerator.writeStartObject(); + if (localRepresentation != null) { + if (localRepresentation.isEnumerated()) { + final ArtefactReference ref = localRepresentation.enumerated(); + final ArtefactReference resolvedRef = referenceResolver.resolve(ref); + jsonGenerator.writeStringField(StructureUtils.ENUMERATION, referenceAdapter.toAdaptedUrn(resolvedRef)); + } else { + Set facets = localRepresentation.nonEnumerated(); + TextFormatImpl textFormat = new TextFormatImpl(facets); + jsonGenerator.writeFieldName("textFormat"); + jsonGenerator.writeStartObject(); + + writeTextFormat(jsonGenerator, textFormat); + + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndObject(); + } + + private void writeTextFormat(JsonGenerator jsonGenerator, TextFormatImpl textFormat) throws IOException { + + StructureUtils.writeCommonFormatAttributes(jsonGenerator, textFormat); + Optional decimals = textFormat.getDecimals(); + if (decimals.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.DECIMALS, decimals.get()); + } + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/SelectionValueWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/SelectionValueWriter.java new file mode 100644 index 0000000..abb37fe --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/SelectionValueWriter.java @@ -0,0 +1,106 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.AfterPeriod; +import com.epam.jsdmx.infomodel.sdmx30.BeforePeriod; +import com.epam.jsdmx.infomodel.sdmx30.LocalisedMemberValue; +import com.epam.jsdmx.infomodel.sdmx30.MemberValue; +import com.epam.jsdmx.infomodel.sdmx30.RangePeriod; +import com.epam.jsdmx.infomodel.sdmx30.SelectionValue; +import com.epam.jsdmx.infomodel.sdmx30.TimeRangePeriod; +import com.epam.jsdmx.infomodel.sdmx30.TimeRangeValue; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.tuple.Pair; + +public class SelectionValueWriter { + + public void writeSelectionValues(JsonGenerator jsonGenerator, List selectionValues) throws IOException { + if (CollectionUtils.isNotEmpty(selectionValues)) { + List timeRanges = selectionValues.stream().filter(Objects::nonNull) + .filter(TimeRangeValue.class::isInstance) + .collect(Collectors.toList()); + writeTimeRanges(jsonGenerator, timeRanges); + + List values = selectionValues.stream().filter(Objects::nonNull) + .filter(value -> !(value instanceof TimeRangeValue)) + .collect(Collectors.toList()); + writeValues(jsonGenerator, values); + + //TODO cascadeValues in question + } + } + + private void writeTimeRanges(JsonGenerator jsonGenerator, List timeRanges) throws IOException { + if (CollectionUtils.isNotEmpty(timeRanges)) { + List> values = new ArrayList<>(); + for (SelectionValue timeRange : timeRanges) { + if (timeRange != null) { + if (timeRange instanceof AfterPeriod) { + AfterPeriod afterPeriod = (AfterPeriod) timeRange; + values.add(Pair.of(afterPeriod, StructureUtils.AFTER_PERIOD)); + } + if (timeRange instanceof BeforePeriod) { + BeforePeriod beforePeriod = (BeforePeriod) timeRange; + values.add(Pair.of(beforePeriod, StructureUtils.BEFORE_PERIOD)); + } + if (timeRange instanceof RangePeriod) { + RangePeriod rangePeriod = (RangePeriod) timeRange; + TimeRangePeriod startPeriod = rangePeriod.getStartPeriod(); + if (startPeriod != null) { + values.add(Pair.of(startPeriod, StructureUtils.START_PERIOD)); + } + TimeRangePeriod endPeriod = rangePeriod.getEndPeriod(); + if (endPeriod != null) { + values.add(Pair.of(endPeriod, StructureUtils.END_PERIOD)); + } + } + } + } + if (CollectionUtils.isNotEmpty(values)) { + jsonGenerator.writeFieldName(StructureUtils.TIME_RANGE); + jsonGenerator.writeStartObject(); + for (Pair value : values) { + writeTimeRangePeriod(jsonGenerator, value.getLeft(), value.getRight()); + } + jsonGenerator.writeEndObject(); + } + } + } + + public void writeTimeRangePeriod(JsonGenerator jsonGenerator, + TimeRangePeriod timeRangePeriod, + String timeRangePeriodName) throws IOException { + String period = timeRangePeriod.getPeriod(); + boolean inclusive = timeRangePeriod.isInclusive(); + jsonGenerator.writeFieldName(timeRangePeriodName); + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField(StructureUtils.PERIOD, period); + jsonGenerator.writeBooleanField(StructureUtils.IS_INCLUSIVE, inclusive); + jsonGenerator.writeEndObject(); + } + + private void writeValues(JsonGenerator jsonGenerator, List memberValues) throws IOException { + if (CollectionUtils.isNotEmpty(memberValues)) { + jsonGenerator.writeFieldName(StructureUtils.VALUES); + jsonGenerator.writeStartArray(); + for (SelectionValue selectionValue : memberValues) { + if (selectionValue instanceof MemberValue) { + MemberValue memberValue = (MemberValue) selectionValue; + jsonGenerator.writeString(memberValue.getValue()); + } + if (selectionValue instanceof LocalisedMemberValue) { + LocalisedMemberValue memberValue = (LocalisedMemberValue) selectionValue; + jsonGenerator.writeString(memberValue.getValue()); + } + } + jsonGenerator.writeEndArray(); + } + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/StructureUtils.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/StructureUtils.java new file mode 100644 index 0000000..0afa33f --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/StructureUtils.java @@ -0,0 +1,297 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.ConstraintRoleType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.infomodel.sdmx30.TextFormatImpl; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.BidiMap; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.bidimap.DualHashBidiMap; +import org.apache.commons.lang3.StringUtils; + +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class StructureUtils { + + public static final String ID = "id"; + public static final String NAME = "name"; + public static final String NAMES = "names"; + public static final String VERSION = "version"; + public static final String AGENCY_ID = "agencyID"; + public static final String DESCRIPTION = "description"; + public static final String DESCRIPTIONS = "descriptions"; + public static final String VALID_TO = "validTo"; + public static final String VALID_FROM = "validFrom"; + + public static final String CATEGORIES = "categories"; + + public static final String ANNOTATIONS = "annotations"; + public static final String TITLE = "title"; + public static final String VALUE = "value"; + public static final String TEXT = "text"; + public static final String TEXTS = "texts"; + public static final String LINKS = "links"; + public static final String URN = "urn"; + public static final String TYPE = "type"; + public static final String REL = "rel"; + + public static final String IS_PARTIAL = "isPartial"; + + public static final String CONCEPT_IDENTITY = "conceptIdentity"; + public static final String LOCAL_REPRESENTATION = "localRepresentation"; + public static final String CORE_REPRESENTATION = "coreRepresentation"; + + public static final String SOURCE = "source"; + public static final String TARGET = "target"; + + public static final String LEVEL = "level"; + + public static final String ATTRIBUTE_LIST = "attributeList"; + public static final String DIMENSION_LIST = "dimensionList"; + public static final String DIMENSIONS = "dimensions"; + public static final String ATTACHMENT_GROUPS = "attachmentGroups"; + public static final String GROUP_DIMENSIONS = "groupDimensions"; + public static final String ATTRIBUTES = "attributes"; + public static final String TIME_DIMENSIONS = "timeDimensions"; + public static final String MEASURE_LIST = "measureList"; + public static final String ATTRIBUTE_RELATIONSHIP = "attributeRelationship"; + public static final String CONCEPT_ROLES = "conceptRoles"; + public static final String POSITION = "position"; + public static final String DIMENSION = "dimension"; + public static final String NONE = "none"; + + public static final String ENUMERATION = "enumeration"; + + + public static final String CONCEPTS = "concepts"; + + public static final String CODE = "code"; + public static final String CODE_ID = "codeID"; + public static final String CODES = "codes"; + public static final String PARENT = "parent"; + public static final String STRUCTURE = "structure"; + + public static final String ROLE = "role"; + + public static final String DATA_STRUCTURE_COMPONENTS = "dataStructureComponents"; + + public static final String HIERARCHICAL_CODES = "hierarchicalCodes"; + public static final String DECIMALS = "decimals"; + public static final String IS_MULTI_LINGUAL = "isMultiLingual"; + public static final String IS_SEQUENCE = "isSequence"; + public static final String INTERVAL = "interval"; + public static final String START_VALUE = "startValue"; + public static final String END_VALUE = "endValue"; + public static final String TIME_INTERVAL = "timeInterval"; + public static final String START_TIME = "startTime"; + public static final String END_TIME = "endTime"; + public static final String MIN_LENGTH = "minLength"; + public static final String MAX_LENGTH = "maxLength"; + public static final String MIN_VALUE = "minValue"; + public static final String MAX_VALUE = "maxValue"; + public static final String PATTERN = "pattern"; + + public static final String DATA = "data"; + public static final String CATEGORISATIONS = "categorisations"; + public static final String CATEGORY_SCHEMES = "categorySchemes"; + public static final String CODE_LISTS = "codelists"; + public static final String CONCEPT_SCHEMES = "conceptSchemes"; + public static final String DATA_STRUCTURES = "dataStructures"; + public static final String HIERARCHIES = "hierarchies"; + public static final String HIERARCHICAL_CODELISTS = "hierarchicalCodelists"; + public static final String DATAFLOWS = "dataflows"; + public static final String METADATAFLOWS = "metadataflows"; + public static final String METADATA_SETS = "metadataSets"; + public static final String METADATA_STRUCTURES = "metadataStructures"; + + public static final String CODING_FORMAT = "codingFormat"; + public static final String SCHEMA = "schema"; + public static final String TEST = "test"; + public static final String PREPARED = "prepared"; + public static final String CONTENT_LANGUAGES = "contentLanguages"; + public static final String SENDER = "sender"; + public static final String META = "meta"; + public static final String URI = "uri"; + + public static final String CONTACTS = "contacts"; + public static final String DEPARTMENT = "department"; + public static final String TELEPHONES = "telephones"; + public static final String FAXES = "faxes"; + public static final String X_400_S = "x400s"; + public static final String URIS = "uris"; + public static final String EMAILS = "emails"; + public static final String AGENCIES = "agencies"; + public static final String AGENCIES_ID = "AGENCIES"; + + public static final String GROUP = "group"; + public static final String GROUPS = "groups"; + public static final String AGENCY_SCHEMES = "agencySchemes"; + public static final String ATTRIBUTE_DESCRIPTOR_ID = "AttributeDescriptor"; + public static final String DIMENSION_DESCRIPTOR_ID = "DimensionDescriptor"; + public static final String MEASURE_DESCRIPTOR_ID = "MeasureDescriptor"; + + public static final String CONTENT_CONSTRAINT = "contentconstraint"; + public static final String METADATA_TARGET_REGIONS = "metadataTargetRegions"; + public static final String RELEASE_CALENDAR = "releaseCalendar"; + public static final String TOLERANCE = "tolerance"; + public static final String OFFSET = "offset"; + public static final String PERIODICITY = "periodicity"; + public static final String CONSTRAINT_ATTACHMENT = "constraintAttachment"; + public static final String DATA_PROVIDER = "dataProvider"; + public static final String PROVISION_AGREEMENTS = "provisionAgreements"; + public static final String DATA_KEY_SETS = "dataKeySets"; + public static final String KEYS = "keys"; + public static final String KEY_VALUES = "keyValues"; + + public static final String CUBE_REGIONS = "cubeRegions"; + public static final String IS_INCLUDED = "isIncluded"; + public static final String INCLUDE = "include"; + public static final String VALUES = "values"; + public static final String TIME_RANGE = "timeRange"; + public static final String START_PERIOD = "startPeriod"; + public static final String END_PERIOD = "endPeriod"; + public static final String BEFORE_PERIOD = "beforePeriod"; + public static final String AFTER_PERIOD = "afterPeriod"; + public static final String PERIOD = "period"; + public static final String IS_INCLUSIVE = "isInclusive"; + public static final BidiMap CONSTRAINT_ROLE_STRING = new DualHashBidiMap<>(); + + public static final String IS_FINAL = "isFinal"; + + public static void writeInternationalString(JsonGenerator jsonGenerator, + InternationalString string, + String fieldName) throws IOException { + if (string != null) { + jsonGenerator.writeFieldName(fieldName); + jsonGenerator.writeStartObject(); + string.getAllAsStream().forEach(entry -> { + final String text = entry.getValue(); + final String locale = entry.getKey(); + if (StringUtils.isNotEmpty(text)) { + try { + jsonGenerator.writeStringField(locale, text); + } catch (IOException e) { + log.error(e.getMessage()); + } + } + }); + + jsonGenerator.writeEndObject(); + } + } + + public static String mapInstantToString(Instant time) { + return time == null ? null : time.toString(); + } + + public static void writeCommonFormatAttributes(JsonGenerator jsonGenerator, TextFormatImpl textFormat) throws IOException { + Optional valueType = textFormat.getValueType(); + if (valueType.isPresent()) { + jsonGenerator.writeStringField("textType", valueType.get().value()); + } + Optional sequence = textFormat.getIsSequence(); + if (sequence.isPresent()) { + jsonGenerator.writeBooleanField(StructureUtils.IS_SEQUENCE, sequence.get()); + } + Optional interval = textFormat.getInterval(); + if (interval.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.INTERVAL, interval.get()); + } + Optional startValue = textFormat.getStartValue(); + if (startValue.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.START_VALUE, startValue.get()); + } + Optional endValue = textFormat.getEndValue(); + if (endValue.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.END_VALUE, endValue.get()); + } + Optional timeInterval = textFormat.getTimeInterval(); + if (timeInterval.isPresent()) { + jsonGenerator.writeStringField(StructureUtils.TIME_INTERVAL, timeInterval.get()); + } + Optional startTime = textFormat.getStartTime(); + if (startTime.isPresent()) { + jsonGenerator.writeStringField(StructureUtils.START_TIME, startTime.get().toString()); + } + Optional endTime = textFormat.getEndTime(); + if (endTime.isPresent()) { + jsonGenerator.writeStringField(StructureUtils.END_TIME, endTime.get().toString()); + } + Optional minLength = textFormat.getMinLength(); + if (minLength.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.MIN_LENGTH, minLength.get()); + } + Optional maxLength = textFormat.getMaxLength(); + if (maxLength.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.MAX_LENGTH, maxLength.get()); + } + Optional minValue = textFormat.getMinValue(); + if (minValue.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.MIN_VALUE, minValue.get()); + } + Optional maxValue = textFormat.getMaxValue(); + if (maxValue.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.MAX_VALUE, maxValue.get()); + } + Optional pattern = textFormat.getPattern(); + if (pattern.isPresent()) { + jsonGenerator.writeStringField(StructureUtils.PATTERN, pattern.get()); + } + } + + public static void writeStringField(JsonGenerator jg, String name, String value) { + if (value != null) { + try { + jg.writeStringField(name, value); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + public static List getArtefactReferencesByStructureClass(List constrainedArtefacts, + StructureClassImpl structureClass) { + return constrainedArtefacts.stream() + .filter(Objects::nonNull) + .filter(reference -> reference.getStructureClass().equals(structureClass)) + .collect(Collectors.toList()); + } + + public static void writeArtefactReferences(JsonGenerator jsonGenerator, + List references, + String refName, + ReferenceAdapter adapter) throws IOException { + if (CollectionUtils.isNotEmpty(references)) { + jsonGenerator.writeFieldName(refName); + jsonGenerator.writeStartArray(); + for (ArtefactReference reference : references) { + if (reference != null) { + jsonGenerator.writeString(adapter.toAdaptedUrn(reference)); + } + } + jsonGenerator.writeEndArray(); + } + } + + static { + CONSTRAINT_ROLE_STRING.put(ConstraintRoleType.ALLOWABLE_CONTENT, "Allowed"); + CONSTRAINT_ROLE_STRING.put(ConstraintRoleType.ACTUAL_CONTENT, "Actual"); + } +} diff --git a/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/VersionableWriter.java b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/VersionableWriter.java new file mode 100644 index 0000000..b6fd983 --- /dev/null +++ b/sdmx-json10/src/main/java/com/epam/jsdmx/json10/structure/writer/VersionableWriter.java @@ -0,0 +1,32 @@ +package com.epam.jsdmx.json10.structure.writer; + +import static com.epam.jsdmx.serializer.util.DateTimeConverterUtil.convertToDateTime; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.VersionableArtefact; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.lang3.StringUtils; + +public class VersionableWriter { + + private final NameableWriter nameableWriter; + + public VersionableWriter(NameableWriter nameableWriter) { + this.nameableWriter = nameableWriter; + } + + public void write(JsonGenerator jsonGenerator, VersionableArtefact artefact) throws IOException { + nameableWriter.write(jsonGenerator, artefact); + jsonGenerator.writeStringField(StructureUtils.VERSION, artefact.getVersion().toString()); + String validTo = convertToDateTime(artefact.getValidToString()); + if (StringUtils.isNotBlank(validTo)) { + jsonGenerator.writeStringField(StructureUtils.VALID_TO, validTo); + } + String validFrom = convertToDateTime(artefact.getValidFromString()); + if (StringUtils.isNotBlank(validFrom)) { + jsonGenerator.writeStringField(StructureUtils.VALID_FROM, validFrom); + } + } +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/MaintainableArtifactsTestUtils.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/MaintainableArtifactsTestUtils.java new file mode 100644 index 0000000..00df32f --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/MaintainableArtifactsTestUtils.java @@ -0,0 +1,1061 @@ +package com.epam.jsdmx.json10.structure; + +import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; + +import java.io.ByteArrayOutputStream; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.AfterPeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.AgencyImpl; +import com.epam.jsdmx.infomodel.sdmx30.AgencySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Annotation; +import com.epam.jsdmx.infomodel.sdmx30.AnnotationImpl; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseFacetImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseTextFormatRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.BeforePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.CascadeValue; +import com.epam.jsdmx.infomodel.sdmx30.CategorisationImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategoryImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodingFormat; +import com.epam.jsdmx.infomodel.sdmx30.CodingFormatImpl; +import com.epam.jsdmx.infomodel.sdmx30.ComponentValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConstraintRoleType; +import com.epam.jsdmx.infomodel.sdmx30.Contact; +import com.epam.jsdmx.infomodel.sdmx30.ContactImpl; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionImpl; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionKeyImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataKeyImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySet; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySetImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponentImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.EnumeratedRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.ExclusiveCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.Facet; +import com.epam.jsdmx.infomodel.sdmx30.FacetType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.GroupDimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchicalCodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableObjectSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.InclusiveCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.IsoConceptReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.infomodel.sdmx30.ItemMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.LevelImpl; +import com.epam.jsdmx.infomodel.sdmx30.LocalisedMemberValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeRefImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataTargetRegionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.ObservationRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.ProvisionAgreement; +import com.epam.jsdmx.infomodel.sdmx30.ProvisionAgreementImpl; +import com.epam.jsdmx.infomodel.sdmx30.RangePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendar; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendarImpl; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.infomodel.sdmx30.SentinelValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.infomodel.sdmx30.TimeDimensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.TimeRangePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; +import com.epam.jsdmx.json10.structure.writer.AnnotableWriter; +import com.epam.jsdmx.json10.structure.writer.AttributeListWriter; +import com.epam.jsdmx.json10.structure.writer.CategorisationWriter; +import com.epam.jsdmx.json10.structure.writer.CategorySchemeWriter; +import com.epam.jsdmx.json10.structure.writer.CodeWriterImpl; +import com.epam.jsdmx.json10.structure.writer.CodelistWriter; +import com.epam.jsdmx.json10.structure.writer.ComponentWriter; +import com.epam.jsdmx.json10.structure.writer.ConceptRoleWriter; +import com.epam.jsdmx.json10.structure.writer.ConceptSchemeWriter; +import com.epam.jsdmx.json10.structure.writer.ContactsWriter; +import com.epam.jsdmx.json10.structure.writer.DataStructureDefinitionWriter; +import com.epam.jsdmx.json10.structure.writer.DataflowWriter; +import com.epam.jsdmx.json10.structure.writer.DefaultHeaderProvider; +import com.epam.jsdmx.json10.structure.writer.DimensionListWriter; +import com.epam.jsdmx.json10.structure.writer.GroupDimensionListWriter; +import com.epam.jsdmx.json10.structure.writer.HierarchicalCodelistWriter; +import com.epam.jsdmx.json10.structure.writer.IdentifiableWriter; +import com.epam.jsdmx.json10.structure.writer.Json10StructureWriter; +import com.epam.jsdmx.json10.structure.writer.LinksWriter; +import com.epam.jsdmx.json10.structure.writer.MeasureListWriter; +import com.epam.jsdmx.json10.structure.writer.MetaWriter; +import com.epam.jsdmx.json10.structure.writer.NameableWriter; +import com.epam.jsdmx.json10.structure.writer.OrganisationWriter; +import com.epam.jsdmx.json10.structure.writer.RepresentationWriter; +import com.epam.jsdmx.json10.structure.writer.VersionableWriter; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; +import com.epam.jsdmx.serializer.common.StubDataStructureLocalRepresentationAdapter; +import com.epam.jsdmx.serializer.sdmx21.ReferenceResolver; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultReferenceAdapter; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public final class MaintainableArtifactsTestUtils { + + /** + * sets common fields for maintainable artefact + * + * @param artefact - artefact to set fields for + */ + public static void setMaintainableArtefact(MaintainableArtefactImpl artefact) { + artefact.setId("ARTEFACT"); + artefact.setVersion(Version.createFromString("1.2")); + artefact.setOrganizationId("IMF"); + artefact.setName(new InternationalString("Maintanable artefact")); + artefact.getName().add(Locale.CANADA_FRENCH.toLanguageTag(), "artefact"); + String date = "2022-07-17T10:11:16Z"; + + artefact.setValidTo(date); + artefact.setValidFrom(date); + artefact.setDescription(new InternationalString("Some artefact")); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("1"); + annotation.setText(new InternationalString("text")); + annotation.setType("type1"); + artefact.addAnnotation(annotation); + } + + /** + * @return Categorisation object + */ + public static CategorisationImpl buildCategorisation() { + CategorisationImpl categorisation = new CategorisationImpl(); + setMaintainableArtefact(categorisation); + IdentifiableArtefactReferenceImpl structureItemReference = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.CATEGORY, + "CAT_TARGET" + ); + + categorisation.setCategorizedBy(structureItemReference); + IdentifiableArtefactReferenceImpl structureReference = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.CATEGORISATION, + null + ); + categorisation.setCategorizedArtefact(structureReference); + return categorisation; + } + + /** + * @return CategoryScheme object + */ + public static CategorySchemeImpl buildCategoryScheme() { + CategorySchemeImpl categoryScheme = new CategorySchemeImpl(); + setMaintainableArtefact(categoryScheme); + categoryScheme.setPartial(true); + CategoryImpl category = new CategoryImpl(); + category.setDescription(new InternationalString("description")); + category.setId("Category-1"); + category.setName(new InternationalString("Category1")); + category.setDescription(new InternationalString("description category 1")); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot"); + category.setAnnotations(List.of(annotation)); + CategoryImpl category2 = new CategoryImpl(); + category2.setDescription(new InternationalString("description category2")); + category2.setId("Category-2"); + category2.setName(new InternationalString("Category2")); + AnnotationImpl annotation2 = new AnnotationImpl(); + annotation2.setId("Annot2"); + category2.setAnnotations(List.of(annotation, annotation2)); + CategoryImpl category3 = new CategoryImpl(); + category3.setDescription(new InternationalString("description category3")); + category3.setId("Category-3"); + category3.setName(new InternationalString("Category3")); + category.setHierarchy(List.of(category2, category3)); + + CategoryImpl category4 = new CategoryImpl(); + category4.setId("Category-4"); + category4.setName(new InternationalString("Category4")); + categoryScheme.setItems(List.of(category, category4)); + return categoryScheme; + } + + /** + * @return Codelist object + */ + public static CodelistImpl buildCodeList() { + CodelistImpl codelist = new CodelistImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(codelist); + codelist.setPartial(true); + codelist.setExtensions(getExtensions()); + fillCodes(codelist); + return codelist; + } + + private static void fillCodes(CodelistImpl codelist) { + CodeImpl code = new CodeImpl(); + code.setDescription(new InternationalString("code 1 desc")); + code.setId("CODE1"); + code.setName(new InternationalString("code 1")); + code.setParentId("CODE2"); + CodeImpl code2 = new CodeImpl(); + code2.setDescription(new InternationalString("code 2 desc")); + code2.setId("CODE2"); + code2.setName(new InternationalString("code 2")); + code2.setHierarchy(List.of(code)); + codelist.setItems(List.of(code, code2)); + } + + private static List getExtensions() { + CodelistExtensionImpl inclusiveCodeListExtension = fillInclusiveCodeListExtension(); + CodelistExtensionImpl exclusiveCodeListExtension = fillExclusiveCodeListExtension(); + return List.of(inclusiveCodeListExtension, exclusiveCodeListExtension); + } + + private static CodelistExtensionImpl fillExclusiveCodeListExtension() { + CodelistExtensionImpl codelistExtension = new CodelistExtensionImpl(); + ExclusiveCodeSelectionImpl exclusiveCodeSelection = new ExclusiveCodeSelectionImpl(); + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setCascadeValue(CascadeValue.FALSE); + memberValue.setValue("mem2"); + exclusiveCodeSelection.setMembers(List.of(memberValue)); + return fillCodeListExtension(codelistExtension, exclusiveCodeSelection); + } + + private static CodelistExtensionImpl fillInclusiveCodeListExtension() { + CodelistExtensionImpl codelistExtension = new CodelistExtensionImpl(); + InclusiveCodeSelectionImpl inclusiveCodeSelection = new InclusiveCodeSelectionImpl(); + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setCascadeValue(CascadeValue.TRUE); + memberValue.setValue("mem1"); + inclusiveCodeSelection.setMembers(List.of(memberValue)); + return fillCodeListExtension(codelistExtension, inclusiveCodeSelection); + } + + private static CodelistExtensionImpl fillCodeListExtension(CodelistExtensionImpl codelistExtension, BaseCodeSelectionImpl codeSelection) { + codelistExtension.setPrefix("PREF2"); + MaintainableArtefactReference maintainableReference = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)"); + codelistExtension.setCodelist(maintainableReference); + codelistExtension.setCodeSelection(codeSelection); + return codelistExtension; + } + + /** + * @return ConceptScheme object + */ + public static ConceptSchemeImpl buildConceptScheme() { + ConceptSchemeImpl conceptScheme = new ConceptSchemeImpl(); + setMaintainableArtefact(conceptScheme); + ConceptImpl concept = new ConceptImpl(); + concept.setId("COUNTRY"); + concept.setName(new InternationalString("Country")); + IsoConceptReferenceImpl isoConceptReference = new IsoConceptReferenceImpl(); + isoConceptReference.setConceptId("Conn"); + isoConceptReference.setAgency("QHB"); + isoConceptReference.setSchemeId("Schema"); + concept.setIsoConceptReference(isoConceptReference); + concept.setCoreRepresentation(getRepresentation()); + conceptScheme.setItems(List.of(concept)); + conceptScheme.setPartial(true); + return conceptScheme; + } + + private static Representation getRepresentation() { + Set facetSet = new HashSet<>(); + BaseFacetImpl facet1 = new BaseFacetImpl(); + BaseFacetImpl facet2 = new BaseFacetImpl(); + facet1.setValueType(FacetValueType.ALPHA); + SentinelValueImpl sentinelValue = new SentinelValueImpl(); + sentinelValue.setValue("val"); + sentinelValue.setName(new InternationalString("sent")); + sentinelValue.setDescription(new InternationalString("sentinel descr")); + facet2.setSentinelValues(List.of(sentinelValue)); + facet2.setType(FacetType.SENTINEL_VALUES); + facet2.setValueType(FacetValueType.ALPHA); + facetSet.addAll(List.of(facet1, facet2)); + return new BaseTextFormatRepresentationImpl(facetSet); + } + + /** + * @return DataConstraint object + */ + public static DataConstraintImpl buildDataConstraint() { + DataConstraintImpl dataConstraint = new DataConstraintImpl(); + setMaintainableArtefact(dataConstraint); + dataConstraint.setConstraintRoleType(ConstraintRoleType.ALLOWABLE_CONTENT); + + LocalisedMemberValueImpl selectionValue = new LocalisedMemberValueImpl(); + selectionValue.setValue("selectionValue local"); + selectionValue.setLocale("en"); + + MemberValueImpl selectionValue1 = new MemberValueImpl(); + selectionValue1.setValue("selectionValue1"); + + MemberSelectionImpl memberSelection1 = new MemberSelectionImpl(); + memberSelection1.setSelectionValues(List.of(selectionValue, selectionValue1)); + memberSelection1.setComponentId("some component id 1"); + memberSelection1.setIncluded(true); + memberSelection1.setRemovePrefix(true); + + MemberValueImpl selectionValue2 = new MemberValueImpl(); + selectionValue2.setValue("selectionValue2"); + selectionValue2.setCascadeValue(CascadeValue.TRUE); + selectionValue2.setValidTo(Instant.parse("2020-05-12T12:00:00.000000Z")); + selectionValue2.setValidFrom(Instant.parse("2020-04-12T12:00:00.000000Z")); + MemberValueImpl selectionValue5 = new MemberValueImpl(); + selectionValue5.setValue("selectionValue5"); + + MemberSelectionImpl memberSelection2 = new MemberSelectionImpl(); + memberSelection2.setSelectionValues(List.of(selectionValue2, selectionValue5)); + memberSelection2.setComponentId("some component id 2"); + memberSelection2.setIncluded(true); + memberSelection2.setRemovePrefix(true); + + BeforePeriodImpl selectionValue3 = new BeforePeriodImpl(); + selectionValue3.setPeriod("2020"); + AfterPeriodImpl selectionValue4 = new AfterPeriodImpl(); + selectionValue4.setPeriod("2021"); + + CubeRegionKeyImpl cubeRegionKey1 = new CubeRegionKeyImpl(); + cubeRegionKey1.setComponentId("123"); + cubeRegionKey1.setIncluded(true); + cubeRegionKey1.setRemovePrefix(true); + cubeRegionKey1.setValidFrom(Instant.parse("2020-04-12T12:00:00.000000Z")); + cubeRegionKey1.setValidTo(Instant.parse("2022-04-12T12:00:00.000000Z")); + cubeRegionKey1.setSelectionValues(List.of(selectionValue3, selectionValue4)); + + CubeRegionImpl cubeRegion = new CubeRegionImpl(); + cubeRegion.setIncluded(true); + cubeRegion.setMemberSelections(List.of(memberSelection1, memberSelection2)); + cubeRegion.setCubeRegionKeys(List.of(cubeRegionKey1)); + cubeRegion.setAnnotations(getAnnotations()); + + dataConstraint.setCubeRegions(List.of(cubeRegion)); + dataConstraint.setReleaseCalendar(createReleaseCalendar()); + dataConstraint.setDataContentKeys(List.of(createDataKeySets())); + dataConstraint.setConstrainedArtefacts(List.of(buildProvisionAgreement().getDataProvider())); + + return dataConstraint; + } + + /** + * @return MetaDataConstraint object + */ + public static MetadataConstraintImpl buildMetadataConstraint() { + MetadataConstraintImpl metadataConstraint = new MetadataConstraintImpl(); + setMaintainableArtefact(metadataConstraint); + metadataConstraint.setConstraintRoleType(ConstraintRoleType.ALLOWABLE_CONTENT); + metadataConstraint.setReleaseCalendar(createReleaseCalendar()); + + IdentifiableArtefactReferenceImpl maintainableArtefactReference = new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)"); + metadataConstraint.setConstrainedArtefacts(List.of(buildProvisionAgreement().getDataProvider(), maintainableArtefactReference)); + + MetadataTargetRegionImpl metadataTargetRegion = new MetadataTargetRegionImpl(); + metadataTargetRegion.setIncluded(true); + List memberSelectionList = getMemberSelections(false, true); + metadataTargetRegion.setMemberSelections(memberSelectionList); + metadataConstraint.setMetadataTargetRegions(List.of(metadataTargetRegion)); + + return metadataConstraint; + } + + /** + * @return DataStructureDefinition object + */ + public static DataStructureDefinitionImpl buildDataStructureDefinition() { + DataStructureDefinitionImpl dataStructureDefinition = new DataStructureDefinitionImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(dataStructureDefinition); + MaintainableArtefactReference maintainableReference = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)"); + dataStructureDefinition.setMetadataStructure(maintainableReference); + dataStructureDefinition.setDimensionDescriptor(fillDimensionDescriptor()); + dataStructureDefinition.setAttributeDescriptor(fillAttributeDescriptor()); + dataStructureDefinition.setMeasureDescriptor(fillMeasureDescriptor()); + dataStructureDefinition.setGroupDimensionDescriptor(fillGroupDimensionDescriptor()); + return dataStructureDefinition; + } + + /** + * @return MetadataStructureDefinition object + */ + public static MetadataStructureDefinitionImpl buildMetadataStructureDefinition() { + MetadataStructureDefinitionImpl metadataStructureDefinition = new MetadataStructureDefinitionImpl(); + setMaintainableArtefact(metadataStructureDefinition); + MetadataAttributeDescriptorImpl metadataAttributeDescriptor = new MetadataAttributeDescriptorImpl(); + metadataAttributeDescriptor.setId("MetadataAttributeDescriptor"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot-1"); + MetadataAttributeImpl metadataAttribute = getMetadataAttribute("meta-1", "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)"); + metadataAttribute.setHierarchy(List.of(getMetadataAttribute("meta-2", "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)"))); + metadataAttributeDescriptor.setComponents(List.of(metadataAttribute)); + metadataAttributeDescriptor.addAnnotation(annotation); + metadataStructureDefinition.setAttributeDescriptor(metadataAttributeDescriptor); + return metadataStructureDefinition; + } + + private static MetadataAttributeImpl getMetadataAttribute(String id, String reference) { + MetadataAttributeImpl metadataAttribute = new MetadataAttributeImpl(); + metadataAttribute.setId(id); + metadataAttribute.setMaxOccurs(20); + metadataAttribute.setMinOccurs(10); + metadataAttribute.setPresentational(true); + Representation representation = new EnumeratedRepresentationImpl( + new MaintainableArtefactReference(reference)); + metadataAttribute.setLocalRepresentation(representation); + metadataAttribute.setConceptIdentity( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DIM")); + return metadataAttribute; + } + + private static List fillGroupDimensionDescriptor() { + GroupDimensionDescriptorImpl d = new GroupDimensionDescriptorImpl(); + d.setId("GROUP1"); + d.setDimensions(List.of("DIM1")); + return List.of(d); + } + + /** + * @return AttributeDescriptor + */ + public static AttributeDescriptorImpl fillAttributeDescriptor() { + AttributeDescriptorImpl attributeDescriptor = new AttributeDescriptorImpl(); + attributeDescriptor.setId("AttributeDescriptor"); + fillMetadata(attributeDescriptor); + fillComponents(attributeDescriptor); + return attributeDescriptor; + } + + + private static void fillComponents(AttributeDescriptorImpl attributeDescriptor) { + DataAttributeImpl dataAttribute = new DataAttributeImpl(); + dataAttribute.setId("DA1"); + dataAttribute.setMinOccurs(0); + DimensionRelationshipImpl rel = new DimensionRelationshipImpl(); + rel.setDimensions(List.of("DIM1")); + rel.setGroupKeys(List.of("GROUP1")); + dataAttribute.setAttributeRelationship(rel); + BaseFacetImpl baseFacet = new BaseFacetImpl(); + baseFacet.setValueType(FacetValueType.ALPHA_NUMERIC); + dataAttribute.setLocalRepresentation(new BaseTextFormatRepresentationImpl(Set.of(baseFacet))); + dataAttribute.setConceptIdentity(new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE")); + dataAttribute.setConceptRoles( + List.of( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE"), + new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE") + )); + MeasureRelationshipImpl measureRelationship = new MeasureRelationshipImpl(); + measureRelationship.setMeasures(List.of("MO")); + dataAttribute.setMeasureRelationship(measureRelationship); + attributeDescriptor.setComponents(List.of(dataAttribute)); + } + + private static void fillMetadata(AttributeDescriptorImpl attributeDescriptor) { + MetadataAttributeRefImpl attributeRef1 = new MetadataAttributeRefImpl(); + attributeRef1.setId("REFERENCE-1"); + attributeRef1.setMetadataRelationship(new ObservationRelationshipImpl()); + MetadataAttributeRefImpl attributeRef2 = new MetadataAttributeRefImpl(); + attributeRef2.setId("REFERENCE-2"); + DimensionRelationshipImpl dimensionRelationship = new DimensionRelationshipImpl(); + dimensionRelationship.setDimensions(List.of("dim1", "dim2")); + attributeRef2.setMetadataRelationship(dimensionRelationship); + MetadataAttributeRefImpl attributeRef3 = new MetadataAttributeRefImpl(); + attributeRef3.setId("REFERENCE-3"); + attributeRef3.setMetadataRelationship(null); + attributeDescriptor.setMetadataAttributes(List.of(attributeRef1, attributeRef2, attributeRef3)); + } + + /** + * @return List + */ + public static List fillListGroupDimensionDescriptor() { + GroupDimensionDescriptorImpl groupDimensionDescriptor1 = new GroupDimensionDescriptorImpl(); + AnnotationImpl annotation1 = new AnnotationImpl(); + annotation1.setId("id1"); + annotation1.setValue("val"); + AnnotationImpl annotation2 = new AnnotationImpl(); + annotation2.setId("id2"); + annotation2.setValue("val"); + groupDimensionDescriptor1.setId("GroupDimensionDescriptor1"); + groupDimensionDescriptor1.setAnnotations(List.of(annotation1, annotation2)); + groupDimensionDescriptor1.setDimensions(List.of("dim1", "dim12")); + + GroupDimensionDescriptorImpl groupDimensionDescriptor2 = new GroupDimensionDescriptorImpl(); + groupDimensionDescriptor2.setId("GroupDimensionDescriptor2"); + groupDimensionDescriptor2.setDimensions(List.of("dim21", "dim22")); + + return List.of(groupDimensionDescriptor1, groupDimensionDescriptor2); + } + + /** + * @return DimensionDescriptor + */ + public static DimensionDescriptorImpl fillDimensionDescriptor() { + DimensionDescriptorImpl dimensionDescriptor = new DimensionDescriptorImpl(); + dimensionDescriptor.setId("DimensionDescriptor"); + fillDimensionComponents(dimensionDescriptor); + return dimensionDescriptor; + } + + private static void fillDimensionComponents(DimensionDescriptorImpl dimensionDescriptor) { + DimensionImpl dimensionComponent = new DimensionImpl(); + dimensionComponent.setOrder(1); + dimensionComponent.setId("DIM1"); + dimensionComponent.setConceptRoles(List.of(new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE"))); + EnumeratedRepresentationImpl enumeratedRepresentation = new EnumeratedRepresentationImpl( + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)")); + dimensionComponent.setLocalRepresentation(enumeratedRepresentation); + dimensionComponent.setConceptIdentity( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE")); + DimensionComponentImpl dimensionTimeComponent = new TimeDimensionImpl(); + dimensionTimeComponent.setId("TIME_PERIOD"); + dimensionTimeComponent.setOrder(2); + dimensionTimeComponent.setConceptIdentity( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE")); + BaseFacetImpl baseFacet = new BaseFacetImpl(); + baseFacet.setValueType(FacetValueType.BASIC_TIME_PERIOD); + dimensionTimeComponent.setLocalRepresentation(new BaseTextFormatRepresentationImpl(Set.of(baseFacet))); + dimensionDescriptor.setComponents(List.of(dimensionComponent, dimensionTimeComponent)); + } + + /** + * @return MeasureDescriptor + */ + public static MeasureDescriptorImpl fillMeasureDescriptor() { + MeasureDescriptorImpl measureDescriptor = new MeasureDescriptorImpl(); + measureDescriptor.setId("MeasureDescriptor"); + fillMeasureComponents(measureDescriptor); + return measureDescriptor; + } + + private static void fillMeasureComponents(MeasureDescriptorImpl measureDescriptor) { + MeasureImpl measure = new MeasureImpl(); + measure.setId("MES1"); + measure.setConceptIdentity(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE")); + measure.setConceptRoles( + List.of( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE"), + new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE") + )); + BaseFacetImpl baseFacet = new BaseFacetImpl(); + baseFacet.setValueType(FacetValueType.BASIC_TIME_PERIOD); + measure.setLocalRepresentation(new BaseTextFormatRepresentationImpl(Set.of(baseFacet))); + measureDescriptor.setComponents(List.of(measure)); + } + + /** + * @return Hierarchy object + */ + public static HierarchyImpl buildHierarchy() { + HierarchyImpl hierarchy = new HierarchyImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(hierarchy); + hierarchy.setHasFormalLevels(true); + HierarchicalCodeImpl code = new HierarchicalCodeImpl(); + code.setId("id"); + code.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1")); + code.setLevelId("Lev1"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("id"); + code.setAnnotations(List.of(annotation)); + String dateStr = "2022-07-17T10:11:16.345Z"; + code.setValidTo(Instant.parse(dateStr)); + code.setValidFrom(Instant.parse(dateStr)); + HierarchicalCodeImpl code2 = new HierarchicalCodeImpl(); + code2.setId("hi-2"); + code2.setLevelId("Lev2"); + code2.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL2")); + code2.setValidTo(Instant.parse(dateStr)); + code2.setValidFrom(Instant.parse(dateStr)); + hierarchy.setCodes(List.of(code, code2)); + LevelImpl level = new LevelImpl(); + level.setDescription(new InternationalString("hierarchy desc")); + level.setName(new InternationalString("hierarchy name")); + level.setId("levId"); + level.setCodeFormat(List.of(fillListOfCodingFormats().get(0))); + hierarchy.setLevel(level); + return hierarchy; + } + + public static HierarchyImpl buildHierarchyWithInnerHierarchy() { + HierarchyImpl hierarchy = new HierarchyImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(hierarchy); + hierarchy.setHasFormalLevels(true); + HierarchicalCodeImpl code = new HierarchicalCodeImpl(); + code.setId("id"); + code.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1")); + code.setLevelId("Lev1"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("id"); + code.setAnnotations(List.of(annotation)); + String dateStr = "2022-07-17T10:11:16.345Z"; + code.setValidTo(Instant.parse(dateStr)); + code.setValidFrom(Instant.parse(dateStr)); + HierarchicalCodeImpl hierarchicalCode = new HierarchicalCodeImpl(); + hierarchicalCode.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1")); + hierarchicalCode.setId("1"); + hierarchicalCode.setValidTo(Instant.parse(dateStr)); + hierarchicalCode.setValidFrom(Instant.parse(dateStr)); + code.setHierarchicalCodes(List.of(hierarchicalCode)); + hierarchy.setCodes(List.of(code)); + LevelImpl level = new LevelImpl(); + level.setDescription(new InternationalString("hierarchy desc")); + level.setName(new InternationalString("hierarchy name")); + level.setId("levId"); + level.setCodeFormat(List.of(fillListOfCodingFormats().get(0))); + hierarchy.setLevel(level); + LevelImpl levelUn = new LevelImpl(); + levelUn.setId("levUn"); + levelUn.setName(new InternationalString("underLevel")); + level.setChild(levelUn); + return hierarchy; + } + + private static List fillListOfCodingFormats() { + List codingFormatList = new ArrayList<>(); + codingFormatList.add(addCodingFormat(FacetType.INTERVAL, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.IS_SEQUENCE, String.valueOf(true))); + codingFormatList.add(addCodingFormat(FacetType.MAX_LENGTH, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.MIN_LENGTH, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.MAX_VALUE, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.MIN_VALUE, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.PATTERN, "a")); + codingFormatList.add(addCodingFormat(FacetType.START_VALUE, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.END_VALUE, String.valueOf(1))); + + CodingFormatImpl codingFormat = new CodingFormatImpl(); + codingFormat.setCodingFormat(new BaseFacetImpl(FacetValueType.fromValue("Alpha"))); + codingFormatList.add(codingFormat); + return codingFormatList; + } + + private static CodingFormat addCodingFormat(FacetType facetType, String value) { + CodingFormatImpl codingFormat = new CodingFormatImpl(); + BaseFacetImpl baseFacet = new BaseFacetImpl(); + baseFacet.setType(facetType); + baseFacet.setValue(value); + codingFormat.setCodingFormat(baseFacet); + return codingFormat; + } + + /** + * @return Metadataflow object + */ + public static MetadataflowImpl buildMetadataFlow() { + MetadataflowImpl metadataflow = new MetadataflowImpl(); + setMaintainableArtefact(metadataflow); + metadataflow.setStructure(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=IMF:METADATA(1.0.0)")); + IdentifiableObjectSelectionImpl objectSelection = new IdentifiableObjectSelectionImpl(); + MaintainableArtefactReference maintainableArtefactReference = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)"); + + MaintainableArtefactReference maintainableArtefactReference2 = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.3)"); + objectSelection.setResolvesTo(List.of(maintainableArtefactReference, maintainableArtefactReference2)); + metadataflow.setSelections(List.of(objectSelection)); + return metadataflow; + } + + /** + * @return Dataflow object + */ + public static DataflowImpl buildDataFlow() { + DataflowImpl dataflow = new DataflowImpl(); + dataflow.setId("DF"); + dataflow.setStructure(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)")); + setMaintainableArtefact(dataflow); + return dataflow; + } + + /** + * @return AgencyScheme + */ + + public static AgencySchemeImpl buildAgencyScheme() { + AgencySchemeImpl agencyScheme = new AgencySchemeImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(agencyScheme); + agencyScheme.setId("AGENCIES"); + agencyScheme.setOrganizationId("SDMX"); + agencyScheme.setVersion(Version.createFromString("1.0")); + AgencyImpl agency1 = createAgency("AG-1"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot"); + agency1.setAnnotations(List.of(annotation)); + AgencyImpl agency2 = createAgency("AG-2"); + + + agencyScheme.setItems(List.of(agency1, agency2)); + return agencyScheme; + } + + private static AgencyImpl createAgency(String id) { + AgencyImpl agency1 = new AgencyImpl(); + agency1.setId(id); + agency1.setName(new InternationalString("Agency")); + agency1.setDescription(new InternationalString("Agency")); + + List contacts = getContacts(); + + agency1.setContacts(contacts); + return agency1; + } + + private static List getContacts() { + ContactImpl contact1 = new ContactImpl(); + contact1.setName("AG_1"); + contact1.setTelephone("9458673082"); + contact1.setFax("somedatafax"); + contact1.setEmail("test@email.com"); + contact1.setOrganizationUnit("IT"); + Map resp = new HashMap<>(); + resp.put("en", "writing"); + resp.put("fr", "ecrire"); + contact1.setResponsibility(new InternationalString(resp)); + contact1.setX400("X400"); + + ContactImpl contact2 = new ContactImpl(); + contact2.setName("AG_2"); + contact2.setTelephone("9458673082"); + contact2.setFax("somedatafax2"); + contact2.setEmail("test@email.com"); + contact2.setOrganizationUnit("IT"); + contact2.setResponsibility(new InternationalString(resp)); + contact2.setX400("X400"); + return List.of(contact1, contact2); + } + + private static ItemMap createItemMap(String target, String source) { + ItemMapImpl itemMap = new ItemMapImpl(); + itemMap.setTarget(target); + itemMap.setSource(source); + itemMap.setValidTo(Instant.parse("2022-07-17T00:00:00Z")); + itemMap.setValidFrom(Instant.parse("2022-07-17T00:00:00Z")); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Ann"); + itemMap.setAnnotations(List.of(annotation)); + return itemMap; + } + + public static VersionableWriter getVersionableWriter() { + final NameableWriter nameableWriter = getNameableWriter(); + return new VersionableWriter(nameableWriter); + } + + public static NameableWriter getNameableWriter() { + final IdentifiableWriter identifiableWriter = getIdentifiableWriter(); + return new NameableWriter(identifiableWriter); + } + + public static IdentifiableWriter getIdentifiableWriter() { + final AnnotableWriter annotableWriter = getAnnotableWriter(); + return new IdentifiableWriter(annotableWriter); + } + + public static AnnotableWriter getAnnotableWriter() { + return new AnnotableWriter(getLinksWriter()); + } + + public static RepresentationWriter getRepresentationWriter() { + return new RepresentationWriter(getReferenceResolver(), new DefaultReferenceAdapter()); + } + + public static ComponentWriter getComponentWriter() { + return new ComponentWriter(getIdentifiableWriter(), getRepresentationWriter(), getReferenceResolver()); + } + + public static ConceptRoleWriter getConceptRoleWriter() { + return new ConceptRoleWriter(getReferenceResolver()); + } + + public static AttributeListWriter getAttributeListWriter() { + return new AttributeListWriter(getIdentifiableWriter(), getConceptRoleWriter(), getComponentWriter()); + } + + public static DimensionListWriter getDimensionListWriter() { + return new DimensionListWriter(getIdentifiableWriter(), getConceptRoleWriter(), getComponentWriter()); + } + + public static GroupDimensionListWriter getGroupDimensionListWriter() { + return new GroupDimensionListWriter(getIdentifiableWriter()); + } + + public static MeasureListWriter getMeasureListWriter() { + return new MeasureListWriter(getIdentifiableWriter(), getConceptRoleWriter(), getComponentWriter()); + } + + public static LinksWriter getLinksWriter() { + return new LinksWriter(getReferenceAdapter()); + } + + public static ContactsWriter getContactsWriter() { + return new ContactsWriter(); + } + + public static OrganisationWriter getOrganisationWriter() { + return new OrganisationWriter(getContactsWriter(), getNameableWriter()); + } + + public static Json10StructureWriter createStructureWriter( + ByteArrayOutputStream outputStream, + ObjectMapper mapper, + DefaultHeaderProvider defaultHeaderProvider) { + ReferenceResolver res = getReferenceResolver(); + final var referenceAdapter = new DefaultReferenceAdapter(); + final var linksWriter = new LinksWriter(referenceAdapter); + final var headerWriter = new MetaWriter(List.of(), defaultHeaderProvider); + final var representationWriter = new RepresentationWriter(res, referenceAdapter); + final var annotableWriter = new AnnotableWriter(linksWriter); + final var identifiableWriter = new IdentifiableWriter(annotableWriter); + final var nameableWriter = new NameableWriter(identifiableWriter); + final var versionableWriter = new VersionableWriter(nameableWriter); + final var componentWriter = new ComponentWriter(identifiableWriter, representationWriter, res); + final var conceptRoleWriter = new ConceptRoleWriter(res); + final var attributeListWriter = new AttributeListWriter(identifiableWriter, conceptRoleWriter, componentWriter); + final var dimensionListWriter = new DimensionListWriter(identifiableWriter, conceptRoleWriter, componentWriter); + final var measureListWriter = new MeasureListWriter(identifiableWriter, conceptRoleWriter, componentWriter); + final var groupDimensionListWriter = new GroupDimensionListWriter(identifiableWriter); + final var categorisationWriter = new CategorisationWriter(versionableWriter, linksWriter, res, referenceAdapter); + final var categorySchemeWriter = new CategorySchemeWriter(versionableWriter, linksWriter, nameableWriter); + final var conceptSchemeWriter = new ConceptSchemeWriter(versionableWriter, linksWriter, nameableWriter, representationWriter); + final var codeImplWriter = new CodeWriterImpl(); + final var codeListWriter = new CodelistWriter(versionableWriter, linksWriter, codeImplWriter, nameableWriter); + final var dataFlowWriter = new DataflowWriter(versionableWriter, linksWriter, res); + final var dataStructureDefinitionWriter = new DataStructureDefinitionWriter( + versionableWriter, + linksWriter, + attributeListWriter, + dimensionListWriter, + measureListWriter, + groupDimensionListWriter, + dsd -> dsd, + new StubDataStructureLocalRepresentationAdapter() + ); + final var hierarchyWriter = new HierarchicalCodelistWriter(versionableWriter, linksWriter, identifiableWriter, nameableWriter, res, referenceAdapter); + + return new Json10StructureWriter( + mapper, + outputStream, + headerWriter, + List.of(categorisationWriter, + categorySchemeWriter, + codeListWriter, + conceptSchemeWriter, + dataStructureDefinitionWriter, + hierarchyWriter, + dataFlowWriter + ) + ); + } + + public static void assertMaintainableArtefactsInJson(String json) { + assertThatJson(json).isPresent(); + assertThatJson(json).node("id") + .isString() + .isEqualTo("ARTEFACT"); + assertThatJson(json).node("version") + .isString() + .isEqualTo("1.2"); + assertThatJson(json).node("agencyID") + .isString() + .isEqualTo("IMF"); + assertThatJson(json).node("name") + .isString() + .isEqualTo("Maintanable artefact"); + assertThatJson(json).node("names") + .isPresent() + .isObject() + .containsEntry("en", "Maintanable artefact"); + assertThatJson(json).node("names") + .isPresent() + .isObject() + .containsEntry("fr-CA", "artefact"); + assertThatJson(json).node("description") + .isString() + .isEqualTo("Some artefact"); + assertThatJson(json).node("descriptions") + .isPresent() + .isObject() + .containsEntry("en", "Some artefact"); + assertThatJson(json).node("annotations") + .isArray() + .element(0) + .node("type") + .isEqualTo("type1"); + assertThatJson(json).node("annotations") + .isArray() + .element(0) + .node("id") + .isString() + .isEqualTo("1"); + } + + private static List getMemberSelections(boolean isSimple, boolean isJson) { + MemberSelectionImpl memberSelection = new MemberSelectionImpl(); + memberSelection.setIncluded(false); + memberSelection.setRemovePrefix(true); + memberSelection.setComponentId("MS"); + + MemberValueImpl memberValue; + if (isSimple) { + memberValue = getMemberValueSimple(); + } else { + memberValue = getMemberValue(); + } + + LocalisedMemberValueImpl localisedMemberValue = new LocalisedMemberValueImpl(); + localisedMemberValue.setValue("local"); + localisedMemberValue.setLocale("en"); + + memberSelection.setSelectionValues(List.of(memberValue, localisedMemberValue)); + + MemberSelectionImpl memberSelection2 = new MemberSelectionImpl(); + memberSelection2.setIncluded(false); + memberSelection2.setRemovePrefix(true); + memberSelection2.setComponentId("MS2"); + BeforePeriodImpl beforePeriod = new BeforePeriodImpl(); + beforePeriod.setInclusive(true); + beforePeriod.setPeriod("2023"); + if (!isJson) { + beforePeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + beforePeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + } + + AfterPeriodImpl afterPeriod = new AfterPeriodImpl(); + afterPeriod.setInclusive(false); + afterPeriod.setPeriod("2028"); + afterPeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + afterPeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + + RangePeriodImpl rangePeriod = new RangePeriodImpl(); + TimeRangePeriodImpl timeRangePeriod = new TimeRangePeriodImpl(); + timeRangePeriod.setInclusive(true); + timeRangePeriod.setPeriod("2022"); + timeRangePeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + timeRangePeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + + rangePeriod.setStartPeriod(timeRangePeriod); + timeRangePeriod.setInclusive(false); + rangePeriod.setEndPeriod(timeRangePeriod); + rangePeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + rangePeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + + memberSelection2.setSelectionValues(List.of(beforePeriod)); + return List.of(memberSelection, memberSelection2); + } + + private static MemberValueImpl getMemberValue() { + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setValue("MEM"); + memberValue.setCascadeValue(CascadeValue.EXCLUDE_ROOT); + memberValue.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + memberValue.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + return memberValue; + } + + private static MemberValueImpl getMemberValueSimple() { + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setValue("MEM"); + return memberValue; + } + + private static ReleaseCalendar createReleaseCalendar() { + ReleaseCalendarImpl releaseCalendar = new ReleaseCalendarImpl(); + releaseCalendar.setOffset("Offset"); + releaseCalendar.setTolerance("Tolerance"); + releaseCalendar.setPeriodicity("Periodicity"); + return releaseCalendar; + } + + private static DataKeySet createDataKeySets() { + DataKeySetImpl dataKeySet = new DataKeySetImpl(); + dataKeySet.setIncluded(true); + DataKeyImpl dataKey = new DataKeyImpl(); + dataKey.setIncluded(true); + ComponentValueImpl componentValue = new ComponentValueImpl(); + componentValue.setIncluded(true); + componentValue.setComponentId("C1"); + componentValue.setRemovePrefix(true); + componentValue.setValue("Value"); + dataKey.setKeyValues(List.of(componentValue)); + dataKey.setMemberSelections(getMemberSelections(true, true)); + dataKey.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + dataKey.setValidTo(Instant.parse("2022-07-17T10:11:16Z")); + dataKeySet.setKeys(List.of(dataKey)); + + return dataKeySet; + } + + public static ProvisionAgreement buildProvisionAgreement() { + ProvisionAgreementImpl provisionAgreement = new ProvisionAgreementImpl(); + setMaintainableArtefact(provisionAgreement); + provisionAgreement.setControlledStructureUsage( + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=IMF:ARTEFACT(1.2)") + ); + provisionAgreement.setDataProvider( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP") + ); + return provisionAgreement; + } + + private static List getAnnotations() { + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot"); + return List.of(annotation); + } + + public static CodeWriterImpl getCodeImplWriter() { + return new CodeWriterImpl(); + } + + public static ReferenceResolver getReferenceResolver() { + // this should be anonymous class, but it is not possible to mock lambda + return new ReferenceResolver() { + @Override + public ArtefactReference resolve(ArtefactReference reference) { + return reference; + } + }; + } + + public static ReferenceAdapter getReferenceAdapter() { + return new DefaultReferenceAdapter(); + } +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/SdmxSourceCompatibilityTester.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/SdmxSourceCompatibilityTester.java new file mode 100644 index 0000000..ecee429 --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/SdmxSourceCompatibilityTester.java @@ -0,0 +1,57 @@ +package com.epam.jsdmx.json10.structure; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.ByteArrayInputStream; +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.util.Set; +import java.util.function.Function; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.sdmxsource.sdmx.api.factory.StructureParserFactory; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; +import org.sdmxsource.sdmx.api.model.beans.base.MaintainableBean; +import org.sdmxsource.sdmx.api.util.ReadableDataLocation; +import org.sdmxsource.sdmx.sdmxbeans.model.SdmxStructureJsonFormat; +import org.sdmxsource.sdmx.structureparser.builder.sdmxbeans.impl.SdmxObjectsJsonV1Builder; +import org.sdmxsource.sdmx.structureparser.factory.SdmxJsonStructureParserFactory; +import org.sdmxsource.util.factory.SdmxSourceReadableDataLocationFactory; + +public class SdmxSourceCompatibilityTester { + + public void test(String serialized, Function> extractor) { + final ReadableDataLocation readableDataLocation = new SdmxSourceReadableDataLocationFactory() + .getReadableDataLocation(new ByteArrayInputStream(serialized.getBytes(StandardCharsets.UTF_8))); + final StructureParserFactory structureParserFactory = new SdmxJsonStructureParserFactory(new SdmxStructureJsonFormat()); + + registerJavaTimeModuleWithinFactor(structureParserFactory); + + SdmxBeans beans = structureParserFactory.getSdmxBeans(readableDataLocation); + assertThat(extractor.apply(beans)).isNotEmpty(); + } + + private static void registerJavaTimeModuleWithinFactor(StructureParserFactory structureParserFactory) { + Field sdmxBeansJsonBuilderField = null; + Field objectMapperField = null; + try { + sdmxBeansJsonBuilderField = structureParserFactory.getClass().getDeclaredField("sdmxBeansJsonBuilder"); + sdmxBeansJsonBuilderField.setAccessible(true); + final var sdmxBeansJsonBuilder = (SdmxObjectsJsonV1Builder) sdmxBeansJsonBuilderField.get(structureParserFactory); + objectMapperField = sdmxBeansJsonBuilder.getClass().getDeclaredField("objectMapper"); + objectMapperField.setAccessible(true); + final var objectMapper = (ObjectMapper) objectMapperField.get(sdmxBeansJsonBuilder); + objectMapper.registerModule(new JavaTimeModule()); + } catch (IllegalAccessException | NoSuchFieldException e) { + throw new RuntimeException(e); + } finally { + if (objectMapperField != null) { + objectMapperField.setAccessible(false); + } + if (sdmxBeansJsonBuilderField != null) { + sdmxBeansJsonBuilderField.setAccessible(false); + } + } + } +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/TestUtils.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/TestUtils.java new file mode 100644 index 0000000..f6aec4e --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/TestUtils.java @@ -0,0 +1,23 @@ +package com.epam.jsdmx.json10.structure; + +public class TestUtils { + + public static final String CATEGORISATION_JSON = "/serialization.expected/categorisation.json"; + public static final String CATEGORY_SCHEMA_JSON = "/serialization.expected/category-schema.json"; + public static final String CODE_LIST_JSON = "/serialization.expected/codelist.json"; + public static final String CONCEPT_SCHEMA_JSON = "/serialization.expected/concept-scheme.json"; + public static final String HIERARCHY_WITH_CHILDREN_JSON = "/serialization.expected/hierarchy.json"; + public static final String HIERARCHY_JSON = "/serialization.expected/hierarchy_flat.json"; + public static final String DATA_FLOW_JSON = "/serialization.expected/data-flow.json"; + public static final String METADATA_FLOW_JSON = "/serialization.expected/metadata-flow.json"; + public static final String METADATA_STRUCTURE_DEF_JSON = "/serialization.expected/metadata-structure-definition.json"; + public static final String DATA_CONSTRAINT_JSON = "/serialization.expected/data-constraint.json"; + public static final String META_DATA_CONSTRAINT_JSON = "/serialization.expected/meta-data-constraint.json"; + public static final String DATA_STRUCTURE_DEFINITION_JSON = "/serialization.expected/data-structure-definition.json"; + + public static final String AGENCY_SCHEME_JSON = "/serialization.expected/agency-scheme.json"; + public static final String DATA_CONSUMER_SCHEME_JSON = "/serialization.expected/data-consumer-scheme.json"; + public static final String DATA_PROVIDER_SCHEME_JSON = "/serialization.expected/data-provider-scheme.json"; + public static final String ORGANISATION_UNIT_SCHEME_JSON = "/serialization.expected/organisation-unit-scheme.json"; + public static final String ORGANISATION_SCHEME_MAP_JSON = "/serialization.expected/organisation-scheme-map.json"; +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/AttributeListWriterJsonTest.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/AttributeListWriterJsonTest.java new file mode 100644 index 0000000..40ec343 --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/AttributeListWriterJsonTest.java @@ -0,0 +1,90 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.json10.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import net.javacrumbs.jsonunit.JsonAssert; +import net.javacrumbs.jsonunit.core.Configuration; +import net.javacrumbs.jsonunit.core.Option; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +class AttributeListWriterJsonTest { + + public static final String ATTRIBUTE_LIST_JSON = "/serialization.expected/attribute-list.json"; + public static final String ATTRIBUTE_LIST_EMPTY_JSON = "/serialization.expected/attribute-list_empty.json"; + + @Spy + private IdentifiableWriter annotableWriterSpy = MaintainableArtifactsTestUtils.getIdentifiableWriter(); + @Spy + private ComponentWriter componentWriterSpy = MaintainableArtifactsTestUtils.getComponentWriter(); + @Spy + private ConceptRoleWriter conceptRoleWriterSpy = MaintainableArtifactsTestUtils.getConceptRoleWriter(); + @InjectMocks + public AttributeListWriter attributeListWriterJson; + + AutoCloseable closeable; + + @BeforeEach + void setup() { + closeable = MockitoAnnotations.openMocks(this); + } + + @AfterEach + void teardown() throws Exception { + closeable.close(); + } + + @Test + void writeAttributeListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + AttributeDescriptorImpl descriptor = MaintainableArtifactsTestUtils.fillAttributeDescriptor(); + + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + jGenerator.writeStartObject(); + try (jGenerator) { + attributeListWriterJson.write(jGenerator, descriptor); + } + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(ATTRIBUTE_LIST_JSON, StandardCharsets.UTF_8); + + JsonAssert.assertJsonEquals(expected, actual, Configuration.empty().withOptions(Option.IGNORING_EXTRA_FIELDS)); + } + + @Test + void writeEmptyAttributeListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + jGenerator.writeStartObject(); + try (jGenerator) { + attributeListWriterJson.write(jGenerator, null); + } + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(ATTRIBUTE_LIST_EMPTY_JSON, StandardCharsets.UTF_8); + JsonAssert.assertJsonEquals(expected, actual, Configuration.empty().withOptions(Option.IGNORING_EXTRA_FIELDS)); + } +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/CategorisationWriterTest.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/CategorisationWriterTest.java new file mode 100644 index 0000000..ae6cf49 --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/CategorisationWriterTest.java @@ -0,0 +1,45 @@ +package com.epam.jsdmx.json10.structure.writer; + + +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.Categorisation; +import com.epam.jsdmx.json10.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.json10.structure.TestUtils; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; + +class CategorisationWriterTest extends JsonWriterTestBase { + + @InjectMocks + public CategorisationWriter categorisationWriter; + + @Test + void writeCategorisationToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Categorisation categorisation = MaintainableArtifactsTestUtils.buildCategorisation(); + + //when + categorisationWriter.writeAndClose(createJsonGenerator(stream), categorisation); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + MaintainableArtifactsTestUtils.assertMaintainableArtefactsInJson(actual); + String expected = IOUtils.resourceToString(TestUtils.CATEGORISATION_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + + sdmxSourceCompatibilityTester.test( + "{ \"meta\": {}, \"data\": { \"categorisations\": [" + actual + "] } }", + SdmxBeans::getCategorisations + ); + } +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/CategorySchemeWriterTest.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/CategorySchemeWriterTest.java new file mode 100644 index 0000000..cc8e028 --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/CategorySchemeWriterTest.java @@ -0,0 +1,44 @@ +package com.epam.jsdmx.json10.structure.writer; + +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeImpl; +import com.epam.jsdmx.json10.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.json10.structure.TestUtils; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; + +class CategorySchemeWriterTest extends JsonWriterTestBase { + + @InjectMocks + public CategorySchemeWriter categorySchemeWriter; + + @Test + void writeCategorySchemeToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + CategorySchemeImpl categoryScheme = MaintainableArtifactsTestUtils.buildCategoryScheme(); + + //when + categorySchemeWriter.writeAndClose(createJsonGenerator(stream), categoryScheme); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + MaintainableArtifactsTestUtils.assertMaintainableArtefactsInJson(actual); + String expected = IOUtils.resourceToString(TestUtils.CATEGORY_SCHEMA_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + + sdmxSourceCompatibilityTester.test( + "{ \"meta\": {}, \"data\": { \"categorySchemes\": [" + actual + "] } }", + SdmxBeans::getCategorySchemes + ); + } +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/CodelistWriterTest.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/CodelistWriterTest.java new file mode 100644 index 0000000..fc7a090 --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/CodelistWriterTest.java @@ -0,0 +1,43 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.Codelist; +import com.epam.jsdmx.json10.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.json10.structure.TestUtils; + +import net.javacrumbs.jsonunit.JsonAssert; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; + +class CodelistWriterTest extends JsonWriterTestBase { + + @InjectMocks + public CodelistWriter codeListWriter; + + @Test + void writeCodeListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Codelist codelist = MaintainableArtifactsTestUtils.buildCodeList(); + + //when + codeListWriter.writeAndClose(createJsonGenerator(stream), codelist); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + MaintainableArtifactsTestUtils.assertMaintainableArtefactsInJson(actual); + String expected = IOUtils.resourceToString(TestUtils.CODE_LIST_JSON, StandardCharsets.UTF_8); + + JsonAssert.assertJsonEquals(expected, actual); + + sdmxSourceCompatibilityTester.test( + "{ \"meta\": {}, \"data\": { \"codelists\": [" + actual + "] } }", + SdmxBeans::getCodelists + ); + } +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/ConceptSchemeWriterTest.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/ConceptSchemeWriterTest.java new file mode 100644 index 0000000..ad2c412 --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/ConceptSchemeWriterTest.java @@ -0,0 +1,44 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.json10.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.json10.structure.TestUtils; + +import net.javacrumbs.jsonunit.JsonAssert; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; + +class ConceptSchemeWriterTest extends JsonWriterTestBase { + + @InjectMocks + public ConceptSchemeWriter conceptSchemeWriter; + + @Test + void writeConceptSchemeToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + ConceptSchemeImpl conceptScheme = MaintainableArtifactsTestUtils.buildConceptScheme(); + + //when + conceptSchemeWriter.writeAndClose(createJsonGenerator(stream), conceptScheme); + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(TestUtils.CONCEPT_SCHEMA_JSON, StandardCharsets.UTF_8); + + JsonAssert.assertJsonEquals(expected, actual); + + sdmxSourceCompatibilityTester.test( + "{ \"meta\": {}, \"data\": { \"conceptSchemes\": [" + actual + "] } }", + SdmxBeans::getConceptSchemes + ); + } + +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/ContentConstraintWriterTest.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/ContentConstraintWriterTest.java new file mode 100644 index 0000000..1df5064 --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/ContentConstraintWriterTest.java @@ -0,0 +1,65 @@ +package com.epam.jsdmx.json10.structure.writer; + +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.DataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataConstraint; +import com.epam.jsdmx.json10.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.json10.structure.TestUtils; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; + +public class ContentConstraintWriterTest extends JsonWriterTestBase { + + @InjectMocks + private ContentConstraintWriter contentConstraintWriter; + + @Test + void writeDataConstraintToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + DataConstraintImpl dataConstraint = MaintainableArtifactsTestUtils.buildDataConstraint(); + + //when + contentConstraintWriter.writeAndClose(createJsonGenerator(stream), dataConstraint); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(TestUtils.DATA_CONSTRAINT_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + + sdmxSourceCompatibilityTester.test( + "{ \"meta\": {}, \"data\": { \"contentconstraint\": [" + actual + "] } }", + SdmxBeans::getContentConstraintBeans + ); + } + + @Test + void writeMetaDataConstraintToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + MetadataConstraint metadataConstraint = MaintainableArtifactsTestUtils.buildMetadataConstraint(); + + //when + contentConstraintWriter.writeAndClose(createJsonGenerator(stream), metadataConstraint); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(TestUtils.META_DATA_CONSTRAINT_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + + sdmxSourceCompatibilityTester.test( + "{ \"meta\": {}, \"data\": { \"contentconstraint\": [" + actual + "] } }", + SdmxBeans::getContentConstraintBeans + ); + } +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/DataStructureDefinitionWriterTest.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/DataStructureDefinitionWriterTest.java new file mode 100644 index 0000000..1ac64d0 --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/DataStructureDefinitionWriterTest.java @@ -0,0 +1,71 @@ +package com.epam.jsdmx.json10.structure.writer; + +import static com.epam.jsdmx.json10.structure.TestUtils.DATA_STRUCTURE_DEFINITION_JSON; +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinition; +import com.epam.jsdmx.json10.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.serializer.common.TimeDimensionLocalRepresentationAdapter; +import com.epam.jsdmx.serializer.sdmx21.DataStructure30To21ComponentAdapter; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Spy; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; + +class DataStructureDefinitionWriterTest extends JsonWriterTestBase { + + @InjectMocks + public DataStructureDefinitionWriter dataStructureDefinitionWriter; + @Spy + private AttributeListWriter attributeListWriterSpy = MaintainableArtifactsTestUtils.getAttributeListWriter(); + @Spy + private DimensionListWriter dimensionListWriterSpy = MaintainableArtifactsTestUtils.getDimensionListWriter(); + @Spy + private MeasureListWriter measureListWriterSpy = MaintainableArtifactsTestUtils.getMeasureListWriter(); + @Spy + private GroupDimensionListWriter groupDimensionListWriter = MaintainableArtifactsTestUtils.getGroupDimensionListWriter(); + @Spy + private DataStructure30To21ComponentAdapter dsdRecomposerSpy = new DataStructure30To21ComponentAdapter() { + @Override + public DataStructureDefinition recompose(DataStructureDefinition dsd) { + return dsd; + } + }; + @Spy + private TimeDimensionLocalRepresentationAdapter dsdAdapterSpy = new TimeDimensionLocalRepresentationAdapter() { + @Override + public DataStructureDefinition adapt(DataStructureDefinition dsd) { + return dsd; + } + }; + + @Test + void writeDataStructureDefinitionToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + DataStructureDefinition dataStructureDefinition = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + + //when + dataStructureDefinitionWriter.writeAndClose(createJsonGenerator(stream), dataStructureDefinition); + String actual = stream.toString(StandardCharsets.UTF_8); + + System.out.println(actual); + //then + String expected = IOUtils.resourceToString(DATA_STRUCTURE_DEFINITION_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + + // commented out due to bug in sdmxsource with npe when initializing dsd with attachment group + sdmxSourceCompatibilityTester.test( + "{ \"meta\": {}, \"data\": { \"dataStructures\": [" + actual + "] } }", + SdmxBeans::getDataStructures + ); + } + +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/DataflowWriterTest.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/DataflowWriterTest.java new file mode 100644 index 0000000..13bad98 --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/DataflowWriterTest.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.json10.structure.writer; + +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.AnnotationImpl; +import com.epam.jsdmx.infomodel.sdmx30.Dataflow; +import com.epam.jsdmx.infomodel.sdmx30.InternationalUri; +import com.epam.jsdmx.json10.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.json10.structure.TestUtils; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; + +class DataflowWriterTest extends JsonWriterTestBase { + @InjectMocks + public DataflowWriter dataFlowWriter; + + @Test + void writeDataFlowToJson() throws IOException, URISyntaxException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Dataflow dataflow = MaintainableArtifactsTestUtils.buildDataFlow(); + AnnotationImpl annotation = (AnnotationImpl) dataflow.getAnnotations() + .get(0); + annotation.setUrl(new InternationalUri(new URI("http://some.com"))); + dataflow.getAnnotations() + .clear(); + dataflow.getAnnotations() + .add(annotation); + + //when + dataFlowWriter.writeAndClose(createJsonGenerator(stream), dataflow); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(TestUtils.DATA_FLOW_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + + sdmxSourceCompatibilityTester.test( + "{ \"meta\": {}, \"data\": { \"dataflows\": [" + actual + "] } }", + SdmxBeans::getDataflows + ); + } +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/DimensionListWriterJsonTest.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/DimensionListWriterJsonTest.java new file mode 100644 index 0000000..1e4669a --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/DimensionListWriterJsonTest.java @@ -0,0 +1,90 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptorImpl; +import com.epam.jsdmx.json10.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import net.javacrumbs.jsonunit.JsonAssert; +import net.javacrumbs.jsonunit.core.Configuration; +import net.javacrumbs.jsonunit.core.Option; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +class DimensionListWriterJsonTest { + + public static final String DIMENSION_LIST_JSON = "/serialization.expected/dimension-list.json"; + public static final String DIMENSION_LIST_EMPTY_JSON = "/serialization.expected/dimension-list_empty.json"; + + @InjectMocks + public DimensionListWriter dimensionListWriterJson; + @Spy + private IdentifiableWriter annotableWriterSpy = MaintainableArtifactsTestUtils.getIdentifiableWriter(); + @Spy + private ComponentWriter componentWriterSpy = MaintainableArtifactsTestUtils.getComponentWriter(); + @Spy + private ConceptRoleWriter conceptRoleWriterSpy = MaintainableArtifactsTestUtils.getConceptRoleWriter(); + + AutoCloseable closeable; + + @BeforeEach + void setup() { + closeable = MockitoAnnotations.openMocks(this); + } + + @AfterEach + void teardown() throws Exception { + closeable.close(); + } + + @Test + void writeDimensionListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + DimensionDescriptorImpl descriptor = MaintainableArtifactsTestUtils.fillDimensionDescriptor(); + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + jGenerator.writeStartObject(); + try (jGenerator) { + dimensionListWriterJson.write(jGenerator, descriptor); + } + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(DIMENSION_LIST_JSON, StandardCharsets.UTF_8); + System.out.println(expected); + JsonAssert.assertJsonEquals(expected, actual, Configuration.empty().withOptions(Option.IGNORING_EXTRA_FIELDS)); + } + + @Test + void writeEmptyDimensionListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + jGenerator.writeStartObject(); + try (jGenerator) { + dimensionListWriterJson.write(jGenerator, null); + } + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(DIMENSION_LIST_EMPTY_JSON, StandardCharsets.UTF_8); + System.out.println(expected); + JsonAssert.assertJsonEquals(expected, actual, Configuration.empty().withOptions(Option.IGNORING_EXTRA_FIELDS)); + } +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/GenericTest.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/GenericTest.java new file mode 100644 index 0000000..eba5689 --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/GenericTest.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.json10.structure.writer; + +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.stream.Stream; + +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactImpl; +import com.epam.jsdmx.json10.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.json10.structure.TestUtils; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class GenericTest extends JsonWriterTestBase { + @ParameterizedTest + @MethodSource("testArtefactWriters") + void writeToJson(String path, MaintainableWriter writer, T artefact) throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + //when + writer.writeAndClose(createJsonGenerator(stream), artefact); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(path, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } + + private static Stream testArtefactWriters() { + + ReferenceAdapter referenceAdapter = MaintainableArtifactsTestUtils.getReferenceAdapter(); + LinksWriter linksWriter = new LinksWriter(referenceAdapter); + AnnotableWriter annotableWriter = new AnnotableWriter(linksWriter); + IdentifiableWriter identifiableWriter = new IdentifiableWriter(annotableWriter); + NameableWriter nameableWriter = new NameableWriter(identifiableWriter); + VersionableWriter versionableWriter = new VersionableWriter(nameableWriter); + ContactsWriter contactsWriter = new ContactsWriter(); + OrganisationWriter organisationWriter = new OrganisationWriter(contactsWriter, nameableWriter); + AgencySchemeWriter agencySchemeWriter = new AgencySchemeWriter(versionableWriter, linksWriter, organisationWriter); + + return Stream.of( + Arguments.of(TestUtils.AGENCY_SCHEME_JSON, agencySchemeWriter, MaintainableArtifactsTestUtils.buildAgencyScheme()) + ); + } +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/GroupDimensionListWriterJsonTest.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/GroupDimensionListWriterJsonTest.java new file mode 100644 index 0000000..a5322e0 --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/GroupDimensionListWriterJsonTest.java @@ -0,0 +1,59 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.GroupDimensionDescriptor; +import com.epam.jsdmx.json10.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import net.javacrumbs.jsonunit.JsonAssert; +import net.javacrumbs.jsonunit.core.Configuration; +import net.javacrumbs.jsonunit.core.Option; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +class GroupDimensionListWriterJsonTest { + public static final String GROUP_DIMENSION_LIST_JSON = "/serialization.expected/group-dimension-list.json"; + + @InjectMocks + public GroupDimensionListWriter groupDimensionListWriter; + @Spy + private IdentifiableWriter identifiableWriter = MaintainableArtifactsTestUtils.getIdentifiableWriter(); + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + } + + @Test + void writeDimensionListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + List descriptors = MaintainableArtifactsTestUtils.fillListGroupDimensionDescriptor().stream() + .map(a -> (GroupDimensionDescriptor) a) + .collect(Collectors.toList()); + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + jGenerator.writeStartObject(); + try (jGenerator) { + groupDimensionListWriter.write(jGenerator, descriptors); + } + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(GROUP_DIMENSION_LIST_JSON, StandardCharsets.UTF_8); + + JsonAssert.assertJsonEquals(expected, actual, Configuration.empty().withOptions(Option.IGNORING_EXTRA_FIELDS)); + } +} \ No newline at end of file diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/HierarchicalCodelistWriterTest.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/HierarchicalCodelistWriterTest.java new file mode 100644 index 0000000..486779f --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/HierarchicalCodelistWriterTest.java @@ -0,0 +1,67 @@ +package com.epam.jsdmx.json10.structure.writer; + +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.Hierarchy; +import com.epam.jsdmx.json10.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.json10.structure.TestUtils; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class HierarchicalCodelistWriterTest extends JsonWriterTestBase { + + @InjectMocks + public HierarchicalCodelistWriter hierarchyWriter; + + @Test + void writeHierarchyToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Hierarchy hierarchy = MaintainableArtifactsTestUtils.buildHierarchy(); + + //when + hierarchyWriter.writeAndClose(createJsonGenerator(stream), hierarchy); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(TestUtils.HIERARCHY_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + + // sdmx source has incorrect expectation about hierarchical codes field name: + // 'codes' VS 'hierarchicalCodes' as per specification + +// sdmxSourceCompatibilityTester.test( +// "{ \"meta\": {}, \"data\": { \"hierarchicalCodelists\": [" + actual + "] } }", +// SdmxBeans::getHierarchicalCodelists +// ); + } + + @Test + void writeHierarchyWithInnerHierarchyToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Hierarchy hierarchy = MaintainableArtifactsTestUtils.buildHierarchyWithInnerHierarchy(); + + //when + hierarchyWriter.writeAndClose(createJsonGenerator(stream), hierarchy); + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(TestUtils.HIERARCHY_WITH_CHILDREN_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + +// sdmxSourceCompatibilityTester.test( +// "{ \"meta\": {}, \"data\": { \"hierarchicalCodelists\": [" + actual + "] } }", +// SdmxBeans::getHierarchicalCodelists +// ); + } +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/Json10StructureWriterTest.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/Json10StructureWriterTest.java new file mode 100644 index 0000000..61bf555 --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/Json10StructureWriterTest.java @@ -0,0 +1,210 @@ +package com.epam.jsdmx.json10.structure.writer; + +import static com.epam.jsdmx.json10.structure.writer.StructureUtils.SCHEMA; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.TreeSet; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorisationImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptScheme; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; +import com.epam.jsdmx.json10.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.serializer.sdmx30.common.Header; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; +import net.javacrumbs.jsonunit.JsonAssert; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class Json10StructureWriterTest { + + public static final String STRUCTURE_JSON = "/serialization.expected/structure.json"; + public static final String EMPTY_STRUCTURE_JSON = "/serialization.expected/empty-structure.json"; + private final ObjectMapper objectMapper = new ObjectMapper(); + private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + private final DefaultHeaderProvider defaultHeaderProvider = mock(DefaultHeaderProvider.class); + private Json10StructureWriter jsonStructureWriter; + + @BeforeEach + @SneakyThrows + void setup() { + jsonStructureWriter = MaintainableArtifactsTestUtils.createStructureWriter( + outputStream, objectMapper, defaultHeaderProvider); + when(defaultHeaderProvider.provide()).thenReturn(buildHeader()); + } + + @SneakyThrows + private Header buildHeader() { + Header header = new Header(); + header.setSchema(new URI(SCHEMA)); + header.setId("IDREF7553"); + header.setContentLanguages(List.of(Locale.ENGLISH)); + header.setTest(false); + header.setPrepared(Instant.parse("2022-04-03T15:35:01Z")); + header.setSender(buildParty()); + return header; + } + + private Party buildParty() { + Party party = new Party(); + party.setId("unknown"); + return party; + } + + @Test + void writeArtefactsToJson() throws IOException { + ArtefactsImpl artefacts = new ArtefactsImpl(); + fillCategorisation(artefacts); + fillCategoryScheme(artefacts); + fillConceptScheme(artefacts); + fillDataFlow(artefacts); + fillCodeList(artefacts); + fillDSD(artefacts); + fillHierarchy(artefacts); + fillMetadataFlow(artefacts); + fillMDSD(artefacts); + fillRepresentationMap(artefacts); + jsonStructureWriter.write(artefacts); + String actual = outputStream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(STRUCTURE_JSON, StandardCharsets.UTF_8); + JsonAssert.assertJsonEquals(expected, actual, JsonAssert.whenIgnoringPaths("meta")); + } + + @Test + void writeEmptyArtefactsToJson() throws IOException { + + ArtefactsImpl artefacts = new ArtefactsImpl(); + jsonStructureWriter.write(artefacts); + String actual = outputStream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(EMPTY_STRUCTURE_JSON, StandardCharsets.UTF_8); + System.out.println(actual); + System.out.println(expected); + JsonAssert.assertJsonEquals(expected, actual, JsonAssert.whenIgnoringPaths("meta")); + } + + private void fillCategoryScheme(ArtefactsImpl artefacts) { + CategorySchemeImpl categoryScheme = new CategorySchemeImpl(); + categoryScheme.setId("CS1"); + categoryScheme.setVersion(Version.createFromString("1.0")); + artefacts.setCategorySchemes(Set.of(categoryScheme)); + } + + private void fillMDSD(ArtefactsImpl artefacts) { + MetadataStructureDefinitionImpl metadataStructureDefinition = new MetadataStructureDefinitionImpl(); + metadataStructureDefinition.setId("MDSD1"); + metadataStructureDefinition.setVersion(Version.createFromString("1.0")); + artefacts.setMetadataStructureDefinitions(Set.of(metadataStructureDefinition)); + } + + private void fillDataFlow(ArtefactsImpl artefacts) { + DataflowImpl dataflow = new DataflowImpl(); + dataflow.setVersion(Version.createFromString("1.0")); + dataflow.setId("DF1"); + artefacts.setDataflows(Set.of(dataflow)); + } + + private void fillConceptScheme(ArtefactsImpl artefacts) { + ConceptSchemeImpl conceptScheme = new ConceptSchemeImpl(); + conceptScheme.setId("CS1"); + conceptScheme.setVersion(Version.createFromString("1.0")); + ConceptSchemeImpl conceptSchemeSec = new ConceptSchemeImpl(); + conceptSchemeSec.setId("CS2"); + conceptSchemeSec.setVersion(Version.createFromString("1.0")); + Set sortedSet = new TreeSet<>(Comparator.comparing(IdentifiableArtefact::getId)); + sortedSet.add(conceptScheme); + sortedSet.add(conceptSchemeSec); + artefacts.setConceptSchemes(sortedSet); + } + + private void fillCategorisation(ArtefactsImpl artefacts) { + CategorisationImpl categorisation = new CategorisationImpl(); + IdentifiableArtefactReferenceImpl structureItemReference = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.CATEGORY, + "CAT_TARGET" + ); + + categorisation.setCategorizedBy(structureItemReference); + IdentifiableArtefactReferenceImpl structureReference = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.CATEGORISATION, + "CAT_SOURCE" + ); + categorisation.setCategorizedArtefact(structureReference); + categorisation.setId("catid"); + categorisation.setVersion(Version.createFromString("1.0")); + categorisation.setDescription(new InternationalString("categ")); + categorisation.setOrganizationId("EPM"); + artefacts.setCategorisations(Set.of(categorisation)); + } + + private void fillCodeList(ArtefactsImpl artefacts) { + CodelistImpl codeList = new CodelistImpl(); + codeList.setId("CL1"); + codeList.setVersion(Version.createFromString("1.0")); + artefacts.setCodelists(Set.of(codeList)); + } + + private void fillDSD(ArtefactsImpl artefacts) { + DataStructureDefinitionImpl dataStructureDefinition = new DataStructureDefinitionImpl(); + dataStructureDefinition.setId("DSD1"); + dataStructureDefinition.setVersion(Version.createFromString("1.0")); + artefacts.setDataStructures(Set.of(dataStructureDefinition)); + } + + private void fillHierarchy(ArtefactsImpl artefacts) { + HierarchyImpl hierarchy = new HierarchyImpl(); + hierarchy.setId("Hi1"); + hierarchy.setVersion(Version.createFromString("1.0")); + artefacts.setHierarchies(Set.of(hierarchy)); + } + + private void fillMetadataFlow(ArtefactsImpl artefacts) { + MetadataflowImpl metadataflow = new MetadataflowImpl(); + metadataflow.setId("MF1"); + metadataflow.setVersion(Version.createFromString("1.0")); + artefacts.setMetadataflows(Set.of(metadataflow)); + } + + private void fillRepresentationMap(ArtefactsImpl artefacts) { + RepresentationMapImpl representationMap = new RepresentationMapImpl(); + representationMap.setId("RM1"); + representationMap.setVersion(Version.createFromString("1.0")); + artefacts.setRepresentationMaps(Set.of(representationMap)); + } +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/JsonWriterTestBase.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/JsonWriterTestBase.java new file mode 100644 index 0000000..91f2803 --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/JsonWriterTestBase.java @@ -0,0 +1,68 @@ +package com.epam.jsdmx.json10.structure.writer; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import com.epam.jsdmx.json10.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.json10.structure.SdmxSourceCompatibilityTester; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; +import com.epam.jsdmx.serializer.sdmx21.ReferenceResolver; + +import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +class JsonWriterTestBase { + + SdmxSourceCompatibilityTester sdmxSourceCompatibilityTester = new SdmxSourceCompatibilityTester(); + + @Spy + private VersionableWriter versionableWriterSpy = MaintainableArtifactsTestUtils.getVersionableWriter(); + @Spy + private LinksWriter linksWriterSpy = MaintainableArtifactsTestUtils.getLinksWriter(); + @Spy + private OrganisationWriter organisationWriter = MaintainableArtifactsTestUtils.getOrganisationWriter(); + @Spy + private AnnotableWriter annotableWriter = MaintainableArtifactsTestUtils.getAnnotableWriter(); + @Spy + private NameableWriter nameableWriter = MaintainableArtifactsTestUtils.getNameableWriter(); + @Spy + private CodeWriterImpl codeWriter = MaintainableArtifactsTestUtils.getCodeImplWriter(); + @Spy + private IdentifiableWriter identifiableWriter = MaintainableArtifactsTestUtils.getIdentifiableWriter(); + @Spy + private RepresentationWriter representationWriter = MaintainableArtifactsTestUtils.getRepresentationWriter(); + @Spy + private ReferenceResolver referenceResolver = MaintainableArtifactsTestUtils.getReferenceResolver(); + @Spy + private ReferenceAdapter referenceAdapter = MaintainableArtifactsTestUtils.getReferenceAdapter(); + @Spy + private DataKeySetsWriter dataKeySetsWriter = new DataKeySetsWriter(); + @Spy + private CubeRegionWriter cubeRegionWriter = new CubeRegionWriter(new SelectionValueWriter(), annotableWriter); + @Spy + private MetadataConstraintWriter metadataConstraintWriter = new MetadataConstraintWriter(new SelectionValueWriter()); + + AutoCloseable closeable; + + @BeforeEach + void setup() { + closeable = MockitoAnnotations.openMocks(this); + } + + @AfterEach + void teardown() throws Exception { + closeable.close(); + } + + public JsonGenerator createJsonGenerator(ByteArrayOutputStream stream) throws IOException { + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + return jGenerator; + } + +} diff --git a/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/MeasureListWriterJsonTest.java b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/MeasureListWriterJsonTest.java new file mode 100644 index 0000000..8bec066 --- /dev/null +++ b/sdmx-json10/src/test/java/com/epam/jsdmx/json10/structure/writer/MeasureListWriterJsonTest.java @@ -0,0 +1,86 @@ +package com.epam.jsdmx.json10.structure.writer; + +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptorImpl; +import com.epam.jsdmx.json10.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +class MeasureListWriterJsonTest { + + public static final String MEASURE_LIST_JSON = "/serialization.expected/measure-list.json"; + public static final String MEASURE_LIST_EMPTY_JSON = "/serialization.expected/measure-list_empty.json"; + @InjectMocks + public MeasureListWriter measureListWriterJson; + @Spy + private IdentifiableWriter annotableWriterSpy = MaintainableArtifactsTestUtils.getIdentifiableWriter(); + @Spy + private ComponentWriter componentWriterSpy = MaintainableArtifactsTestUtils.getComponentWriter(); + @Spy + private ConceptRoleWriter conceptRoleWriterSpy = MaintainableArtifactsTestUtils.getConceptRoleWriter(); + + AutoCloseable closeable; + + @BeforeEach + void setup() { + closeable = MockitoAnnotations.openMocks(this); + } + + @AfterEach + void teardown() throws Exception { + closeable.close(); + } + + @Test + void writeMeasureListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + MeasureDescriptorImpl descriptor = MaintainableArtifactsTestUtils.fillMeasureDescriptor(); + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + jGenerator.writeStartObject(); + try (jGenerator) { + measureListWriterJson.write(jGenerator, descriptor); + } + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(MEASURE_LIST_JSON, StandardCharsets.UTF_8); + assertJsonEquals(expected, actual); + } + + @Test + void writeEmptyMeasureListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + jGenerator.writeStartObject(); + try (jGenerator) { + measureListWriterJson.write(jGenerator, null); + } + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(MEASURE_LIST_EMPTY_JSON, StandardCharsets.UTF_8); + assertJsonEquals(expected, actual); + } +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/category-schema2.json b/sdmx-json10/src/test/resources/deserialization.expected/category-schema2.json new file mode 100644 index 0000000..f4a0f85 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/category-schema2.json @@ -0,0 +1,37 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Categorisation=IMF:ARTEFACT(1.2)", + "type": "categorisation", + "rel": "self" + } + ], + "isPartial": true, + "categories": [] +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/deserialization.expected/codelist_wild.json b/sdmx-json10/src/test/resources/deserialization.expected/codelist_wild.json new file mode 100644 index 0000000..33af17e --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/codelist_wild.json @@ -0,0 +1,89 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:ARTEFACT(1.2)", + "type": "codelist", + "rel": "self" + } + ], + "isPartial": true, + "codes": [ + { + "annotations": [], + "id": "CODE1", + "name": "code 1", + "names": { + "en": "code 1" + }, + "description": "code 1 desc", + "descriptions": { + "en": "code 1 desc" + }, + "parent": "CODE2" + }, + { + "annotations": [], + "id": "CODE2", + "name": "code 2", + "names": { + "en": "code 2" + }, + "description": "code 2 desc", + "descriptions": { + "en": "code 2 desc" + } + } + ], + "codelistExtensions": [ + { + "prefix": "PREF2", + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "inclusiveCodeSelection": { + "memberValues": [ + { + "value": "mem1", + "cascadeSelection": "true" + } + ] + } + }, + { + "prefix": "PREF2", + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "exclusiveCodeSelection": { + "memberValues": [ + { + "value": "mem2", + "cascadeSelection": "false" + } + ] + } + } + ] +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/concept-schema.json b/sdmx-json10/src/test/resources/deserialization.expected/concept-schema.json new file mode 100644 index 0000000..c563577 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/concept-schema.json @@ -0,0 +1,66 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ARTEFACT(1.2)", + "type": "conceptscheme", + "rel": "self" + } + ], + "concepts": [ + { + "annotations": [], + "id": "COUNTRY", + "name": "Country", + "names": { + "en": "Country" + }, + "coreRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + }, + { + "annotations": [], + "id": "COUNTRY2", + "name": "Country", + "names": { + "en": "Country" + }, + "coreRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)", + "enumerationFormat": { + "pattern": "RYtGKbgicZaHCBRQDSx" + } + } + } + ], + "isPartial": true +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/deserialization.expected/data-flow.json b/sdmx-json10/src/test/resources/deserialization.expected/data-flow.json new file mode 100644 index 0000000..429cb03 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/data-flow.json @@ -0,0 +1,41 @@ +{ + "agencyID": "IMF", + "id": "1", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + }, + "links": [ + { + "uri": "http://some.com" + } + ] + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=12:1(1.2)", + "type": "dataflow", + "rel": "self" + } + ], + "structure": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-attr.json b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-attr.json new file mode 100644 index 0000000..3bdfd15 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-attr.json @@ -0,0 +1,94 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)", + "type": "datastructure", + "rel": "self" + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [ + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-1", + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-2", + "attributeRelationship": { + "dimensions": [ + "dim1", + "dim2" + ] + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-3", + "attributeRelationship": { + "none": {} + } + } + ], + "attributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "annotations": [], + "id": "DA1", + "isMandatory": false, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "group": "GroupKey" + }, + "measureRelationship": [ + "MO" + ], + "localRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + } + ] + }, + "dimensionList": {}, + "measureList": {} + } +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-attr_and_null.json b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-attr_and_null.json new file mode 100644 index 0000000..e4efb94 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-attr_and_null.json @@ -0,0 +1,94 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)", + "type": "datastructure", + "rel": "self" + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [ + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-1", + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-2", + "attributeRelationship": { + "dimensions": [ + "dim1", + "dim2" + ] + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-3", + "attributeRelationship": { + "none": {} + } + } + ], + "attributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "annotations": [], + "id": "DA1", + "isMandatory": false, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "group": "GroupKey" + }, + "measureRelationship": [ + "MO" + ], + "localRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + } + ] + }, + "dimensionList": null, + "measureList": null + } +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-attr_null.json b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-attr_null.json new file mode 100644 index 0000000..03b4110 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-attr_null.json @@ -0,0 +1,94 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)", + "type": "datastructure", + "rel": "self" + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": null, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "annotations": [], + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE" + ], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "annotations": [], + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod" + } + } + } + ] + }, + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "MES1", + "isMandatory": false, + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod", + "isMultiLingual": false + } + } + } + ] + } + } +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-components_empty.json b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-components_empty.json new file mode 100644 index 0000000..ce206b4 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-components_empty.json @@ -0,0 +1,41 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)", + "type": "datastructure", + "rel": "self" + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": {}, + "dimensionList": {}, + "measureList": {} + } +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-components_null.json b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-components_null.json new file mode 100644 index 0000000..def0ab3 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-components_null.json @@ -0,0 +1,41 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)", + "type": "datastructure", + "rel": "self" + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": null, + "dimensionList": null, + "measureList": null + } +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-dim.json b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-dim.json new file mode 100644 index 0000000..7df7d28 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-dim.json @@ -0,0 +1,73 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)", + "type": "datastructure", + "rel": "self" + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": {}, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "annotations": [], + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE" + ], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "annotations": [], + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod" + } + } + } + ] + }, + "measureList": {} + } +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-dim_and_null.json b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-dim_and_null.json new file mode 100644 index 0000000..ff0a5d9 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-dim_and_null.json @@ -0,0 +1,73 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)", + "type": "datastructure", + "rel": "self" + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": null, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "annotations": [], + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE" + ], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "annotations": [], + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod" + } + } + } + ] + }, + "measureList": null + } +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-dim_null.json b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-dim_null.json new file mode 100644 index 0000000..18d1555 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-dim_null.json @@ -0,0 +1,115 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)", + "type": "datastructure", + "rel": "self" + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [ + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-1", + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-2", + "attributeRelationship": { + "dimensions": [ + "dim1", + "dim2" + ] + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-3", + "attributeRelationship": { + "none": {} + } + } + ], + "attributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "annotations": [], + "id": "DA1", + "isMandatory": false, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "group": "GroupKey" + }, + "measureRelationship": [ + "MO" + ], + "localRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + } + ] + }, + "dimensionList": null, + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "MES1", + "isMandatory": true, + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod", + "isMultiLingual": false + } + } + } + ] + } + } +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-full.json b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-full.json new file mode 100644 index 0000000..3190f8b --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-full.json @@ -0,0 +1,147 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)", + "type": "datastructure", + "rel": "self" + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [ + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-1", + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-2", + "attributeRelationship": { + "dimensions": [ + "dim1", + "dim2" + ] + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-3", + "attributeRelationship": { + "none": {} + } + } + ], + "attributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "annotations": [], + "id": "DA1", + "isMandatory": false, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "group": "GroupKey" + }, + "measureRelationship": [ + "MO" + ], + "localRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + } + ] + }, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "annotations": [], + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE" + ], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "annotations": [], + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod" + } + } + } + ] + }, + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "MES1", + "isMandatory": false, + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod", + "isMultiLingual": false + } + } + } + ] + } + } +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-meas.json b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-meas.json new file mode 100644 index 0000000..42c4f99 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-meas.json @@ -0,0 +1,62 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)", + "type": "datastructure", + "rel": "self" + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": {}, + "dimensionList": {}, + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "MES1", + "isMandatory": true, + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod", + "isMultiLingual": false + } + } + } + ] + } + } +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-meas_and_null.json b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-meas_and_null.json new file mode 100644 index 0000000..9f0fc37 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-meas_and_null.json @@ -0,0 +1,62 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)", + "type": "datastructure", + "rel": "self" + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": null, + "dimensionList": null, + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "MES1", + "isMandatory": true, + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod", + "isMultiLingual": false + } + } + } + ] + } + } +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-meas_null.json b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-meas_null.json new file mode 100644 index 0000000..7051230 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/data-structure-definition-meas_null.json @@ -0,0 +1,126 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)", + "type": "datastructure", + "rel": "self" + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [ + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-1", + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-2", + "attributeRelationship": { + "dimensions": [ + "dim1", + "dim2" + ] + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-3", + "attributeRelationship": { + "none": {} + } + } + ], + "attributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "annotations": [], + "id": "DA1", + "isMandatory": false, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "group": "GroupKey" + }, + "measureRelationship": [ + "MO" + ], + "localRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + } + ] + }, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "annotations": [], + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE" + ], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "annotations": [], + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod" + } + } + } + ] + }, + "measureList": null + } +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/hierarchy.json b/sdmx-json10/src/test/resources/deserialization.expected/hierarchy.json new file mode 100644 index 0000000..88c9a40 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/hierarchy.json @@ -0,0 +1,88 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.codelist.Hierarchy=IMF:ARTEFACT(1.2)", + "type": "hierarchy", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "hasFormalLevels": true, + "hierarchicalCodes": [ + { + "annotations": [ + { + "id": "id", + "title": null, + "type": null, + "value": null, + "text": null + } + ], + "id": "id", + "validFrom": "2022-07-17T10:11:16.345Z", + "validTo": "2022-07-17T10:11:16.345Z", + "code": "urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1", + "level": "Lev1", + "hierarchicalCodes": [ + { + "annotations": [], + "id": "1", + "validFrom": "2022-07-17T10:11:16.345Z", + "validTo": "2022-07-17T10:11:16.345Z", + "code": "urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1", + "level": null + } + ] + } + ], + "level": { + "annotations": [], + "id": "levId", + "name": "hierarchy name", + "names": { + "en": "hierarchy name" + }, + "description": "hierarchy desc", + "descriptions": { + "en": "hierarchy desc" + }, + "codingFormat": { + "interval": 1 + }, + "level": { + "annotations": [], + "id": "levUn", + "name": "underLevel", + "names": { + "en": "underLevel" + }, + "codingFormat": {} + } + } +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/deserialization.expected/json.json b/sdmx-json10/src/test/resources/deserialization.expected/json.json new file mode 100644 index 0000000..cbacccb --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/json.json @@ -0,0 +1,158 @@ +{ + "data": { + "categorisations": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Categorisation=IMF:ARTEFACT(1.2)", + "type": "categorisation", + "rel": "self" + } + ], + "source": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Categorisation=IMF:ARTEFACT(1.2).CAT_SOURCE", + "target": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Category=IMF:ARTEFACT(1.2).CAT_TARGET" + } + ], + "structureMaps": [ + { + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "id": "FR1", + "annotations": [] + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "id": "FR2", + "annotations": [] + }, + { + "frequencyId": "CODE_3", + "datePattern": "2022-11", + "id": "FR3", + "annotations": [] + } + ], + "datePatternMaps": [ + { + "mappedComponents": [ + { + "source": "CompMapDPS", + "target": "CompMapDPT" + } + ], + "mappedFrequencies": [ + "FR1", + "FR2" + ], + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "DP1", + "locale": "EN", + "yearStart": {}, + "sourcePattern": "SOURCE" + } + ], + "fixedValueMaps": [ + { + "annotations": [], + "value": "value" + } + ], + "epochMaps": [ + { + "basePeriod": "2022-07-17T10:11:16.000000", + "mappedComponents": [ + { + "source": "CompMapEpochS", + "target": "CompMapEpochT" + } + ], + "mappedFrequencies": [ + "FR3" + ], + "epochPeriod": "Microsecond", + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "EPOCH1", + "yearStart": {} + } + ], + "componentMaps": [ + { + "source": [ + "CompMapRepS" + ], + "target": [ + "CompMapRepT" + ], + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)" + } + ], + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16.000000", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.structuremapping.StructureMap=QUANTHUB:STRUC_ID(1.2)", + "rel": "self", + "type": "structuremap" + } + ], + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16.000000" + } + ] + } +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/deserialization.expected/metadata-all-artefacts.json b/sdmx-json10/src/test/resources/deserialization.expected/metadata-all-artefacts.json new file mode 100644 index 0000000..59106b4 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/metadata-all-artefacts.json @@ -0,0 +1,74 @@ +{ + "data": { + "metadataSets": [ + { + "metadataflow": "urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=EPM:MetadataSet(1.8)", + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "reportingEnd": "2022", + "validFrom": "2022-07-17T10:11:16Z", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "targets": [ + "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataSet=EPM:MetadataSetTar(1.8)" + ], + "reportingBegin": "2022", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "publicationPeriod": "2022-03", + "publicationYear": "2022", + "action": "Append", + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataSet=12:1(1.2)", + "rel": "self", + "type": "metadataset" + } + ], + "attributes": [ + { + "id": "attr1", + "value": "someVal", + "attributes": [ + { + "id": "attr2", + "value": "someVal2" + } + ] + } + ], + "id": "1", + "validTo": "2022-07-17T10:11:16Z" + } + ] + }, + "meta": { + "schema": "https://raw.githubusercontent.com/sdmx-twg/sdmx-json/master/metadata-message/tools/schemas/2.0.0/sdmx-json-metadata-schema.json", + "id": "IDREF8124", + "test": false, + "prepared": "2021-11-02T09:47:41.000000", + "contentLanguages": [ + "en" + ], + "sender": { + "id": "unknown" + } + } +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/structure-maps-full.json b/sdmx-json10/src/test/resources/deserialization.expected/structure-maps-full.json new file mode 100644 index 0000000..17e86dc --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/structure-maps-full.json @@ -0,0 +1,119 @@ +{ + "data": { + "structureMaps": [ + { + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "id": "FR1", + "annotations": [] + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "id": "FR2", + "annotations": [] + }, + { + "frequencyId": "CODE_3", + "datePattern": "2022-11", + "id": "FR3", + "annotations": [] + } + ], + "datePatternMaps": [ + { + "mappedComponents": [ + { + "source": "CompMapDPS", + "target": "CompMapDPT" + } + ], + "mappedFrequencies": [ + "FR1", + "FR2" + ], + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "DP1", + "locale": "EN", + "yearStart": {}, + "sourcePattern": "SOURCE" + } + ], + "fixedValueMaps": [ + { + "annotations": [], + "value": "value" + } + ], + "epochMaps": [ + { + "basePeriod": "2022-07-17T10:11:16.000000", + "mappedComponents": [ + { + "source": "CompMapEpochS", + "target": "CompMapEpochT" + } + ], + "mappedFrequencies": [ + "FR3" + ], + "epochPeriod": "Microsecond", + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "EPOCH1", + "yearStart": {} + } + ], + "componentMaps": [ + { + "source": [ + "CompMapRepS" + ], + "target": [ + "CompMapRepT" + ], + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)" + } + ], + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16.000000", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.structuremapping.StructureMap=IMF:ARTEFACT(1.2)", + "rel": "self", + "type": "structuremap" + } + ], + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16.000000" + } + ] + } +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/deserialization.expected/structure-maps-list-full.json b/sdmx-json10/src/test/resources/deserialization.expected/structure-maps-list-full.json new file mode 100644 index 0000000..55c0a9a --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/structure-maps-list-full.json @@ -0,0 +1,201 @@ +{ + "data": { + "structureMaps": [ + { + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "id": "FR1", + "annotations": [] + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "id": "FR2", + "annotations": [] + }, + { + "frequencyId": "CODE_3", + "datePattern": "2022-11", + "id": "FR3", + "annotations": [] + } + ], + "datePatternMaps": [ + { + "mappedComponents": [ + { + "source": "CompMapDPS", + "target": "CompMapDPT" + } + ], + "mappedFrequencies": [ + "FR1", + "FR2" + ], + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "DP1", + "locale": "EN", + "yearStart": {}, + "sourcePattern": "SOURCE" + } + ], + "fixedValueMaps": [ + { + "annotations": [], + "value": "value" + } + ], + "epochMaps": [ + { + "basePeriod": "2022-07-17T10:11:16.000000", + "mappedComponents": [ + { + "source": "CompMapEpochS", + "target": "CompMapEpochT" + } + ], + "mappedFrequencies": [ + "FR3" + ], + "epochPeriod": "Microsecond", + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "EPOCH1", + "yearStart": {} + } + ], + "componentMaps": [ + { + "source": [ + "CompMapRepS" + ], + "target": [ + "CompMapRepT" + ], + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)" + } + ], + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16.000000", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.structuremapping.StructureMap=IMF:ARTEFACT(1.2)", + "rel": "self", + "type": "structuremap" + } + ], + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16.000000" + }, + { + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "id": "FR1", + "annotations": [] + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "id": "FR2", + "annotations": [] + } + ], + "datePatternMaps": [ + { + "mappedComponents": [ + { + "source": "CompMapDPS", + "target": "CompMapDPT" + } + ], + "mappedFrequencies": [ + "FR1", + "FR2" + ], + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "DP1", + "locale": "EN", + "yearStart": {}, + "sourcePattern": "SOURCE" + } + ], + "componentMaps": [ + { + "source": [ + "CompMapRepS" + ], + "target": [ + "CompMapRepT" + ], + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=QUANTHUB:STRUC_ID2(1.2).REPRES" + } + ], + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "QUANTHUB", + "validFrom": "2022-07-17T10:11:16.000000", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.structuremapping.StructureMap=QUANTHUB:STRUC_ID2(1.2)", + "rel": "self", + "type": "structuremap" + } + ], + "id": "STRUC_ID2", + "validTo": "2022-07-17T10:11:16.000000" + } + ] + } +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/deserialization.expected/structures-all-artefacts.json b/sdmx-json10/src/test/resources/deserialization.expected/structures-all-artefacts.json new file mode 100644 index 0000000..a495ae5 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/structures-all-artefacts.json @@ -0,0 +1,811 @@ +{ + "data": { + "categorisations": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Categorisation=IMF:ARTEFACT(1.2)", + "type": "categorisation", + "rel": "self" + } + ], + "source": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Categorisation=IMF:ARTEFACT(1.2).CAT_SOURCE", + "target": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Category=IMF:ARTEFACT(1.2).CAT_TARGET" + } + ], + "structureMaps": [ + { + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "id": "FR1", + "annotations": [] + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "id": "FR2", + "annotations": [] + }, + { + "frequencyId": "CODE_3", + "datePattern": "2022-11", + "id": "FR3", + "annotations": [] + } + ], + "datePatternMaps": [ + { + "mappedComponents": [ + { + "source": "CompMapDPS", + "target": "CompMapDPT" + } + ], + "mappedFrequencies": [ + "FR1", + "FR2" + ], + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "DP1", + "locale": "EN", + "yearStart": {}, + "sourcePattern": "SOURCE" + } + ], + "fixedValueMaps": [ + { + "annotations": [], + "value": "value" + } + ], + "epochMaps": [ + { + "basePeriod": "2022-07-17T10:11:16.000000", + "mappedComponents": [ + { + "source": "CompMapEpochS", + "target": "CompMapEpochT" + } + ], + "mappedFrequencies": [ + "FR3" + ], + "epochPeriod": "Microsecond", + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "EPOCH1", + "yearStart": {} + } + ], + "componentMaps": [ + { + "source": [ + "CompMapRepS" + ], + "target": [ + "CompMapRepT" + ], + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)" + } + ], + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16.000000", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.structuremapping.StructureMap=IMF:ARTEFACT(1.2)", + "rel": "self", + "type": "structuremap" + } + ], + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16.000000" + } + ], + "categorySchemes": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:ARTEFACT(1.2)", + "type": "categoryscheme", + "rel": "self" + } + ], + "isPartial": true, + "categories": [ + { + "annotations": [], + "id": "23423", + "name": "Category1", + "names": { + "en": "Category1" + }, + "description": "description", + "descriptions": { + "en": "description" + }, + "categories": [ + { + "annotations": [], + "id": "23422", + "name": "Category2", + "names": { + "en": "Category2" + }, + "description": "description category1", + "descriptions": { + "en": "description category1" + } + } + ] + } + ] + } + ], + "codeLists": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:ARTEFACT(1.2)", + "type": "codelist", + "rel": "self" + } + ], + "isPartial": true, + "codes": [ + { + "annotations": [], + "id": "CODE1", + "name": "code 1", + "names": { + "en": "code 1" + }, + "description": "code 1 desc", + "descriptions": { + "en": "code 1 desc" + }, + "parent": "CODE2" + }, + { + "annotations": [], + "id": "CODE2", + "name": "code 2", + "names": { + "en": "code 2" + }, + "description": "code 2 desc", + "descriptions": { + "en": "code 2 desc" + } + } + ], + "codelistExtensions": [ + { + "prefix": "PREF2", + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "inclusiveCodeSelection": { + "memberValues": [ + { + "value": "mem1", + "cascadeSelection": "true" + } + ] + } + }, + { + "prefix": "PREF2", + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "exclusiveCodeSelection": { + "memberValues": [ + { + "value": "mem2", + "cascadeSelection": "false" + } + ] + } + } + ] + } + ], + "conceptSchemes": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ARTEFACT(1.2)", + "type": "conceptscheme", + "rel": "self" + } + ], + "concepts": [ + { + "annotations": [], + "id": "COUNTRY", + "name": "Country", + "names": { + "en": "Country" + }, + "coreRepresentation": {} + } + ] + } + ], + "dataStructures": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=12:1(1.2)", + "type": "datastructure", + "rel": "self" + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [ + { + "annotations": [], + "metadataAttributeReference": "12", + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "metadataAttributeReference": "1", + "attributeRelationship": { + "dimensions": [ + "dim1", + "dim2" + ] + } + }, + { + "annotations": [], + "metadataAttributeReference": "2", + "attributeRelationship": { + "none": {} + } + } + ], + "attributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "annotations": [], + "id": "DA1", + "isMandatory": true, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "none": {} + }, + "measureRelationship": [ + "MO" + ], + "localRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + } + ] + }, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "annotations": [], + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "annotations": [], + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": {} + } + ] + }, + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "MES1", + "isMandatory": true, + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod", + "isMultiLingual": false + } + } + } + ] + } + } + } + ], + "hierarchies": [ + { + "level": { + "names": { + "en": "hierarchy name" + }, + "name": "hierarchy name", + "annotations": [], + "description": "hierarchy desc", + "id": "levId", + "descriptions": { + "en": "hierarchy desc" + }, + "codingFormat": { + "interval": 1, + "isSequence": true, + "maxLength": 1, + "minLength": 1, + "maxValue": 1, + "minValue": 1, + "pattern": "a", + "startValue": 1, + "endValue": 1, + "dataType": "Alpha" + } + }, + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16.000000", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "hierarchicalCodes": [ + { + "code": "urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1", + "level": "Lev1", + "annotations": [], + "validFrom": "2022-07-17T10:11:16.345Z", + "validTo": "2022-07-17T10:11:16.345Z" + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.codelist.Hierarchy=IMF:ARTEFACT(1.2)", + "rel": "self", + "type": "hierarchy" + } + ], + "id": "ARTEFACT", + "hasFormalLevels": true, + "validTo": "2022-07-17T10:11:16.000000" + } + ], + "metadataflows": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=IMF:ARTEFACT(1.2)", + "type": "metadataflow", + "rel": "self" + } + ], + "structure": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=IMF:METADATA(1.0.0)" + } + ], + "metadataStructures": [ + { + "metadataStructureComponents": { + "metadataAttributeList": { + "annotations": [ + { + "id": "Annot-1", + "text": null, + "title": null, + "type": null, + "value": null + } + ], + "metadataAttributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataAttributeDescriptor=1:1(1.0).2", + "minOccurs": 10, + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=EPM:dim1(1.0)" + }, + "annotations": [], + "maxOccurs": 20, + "id": "1", + "isPresentational": true, + "metadataAttributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataAttributeDescriptor=1:1(1.0).2", + "minOccurs": 10, + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=EPM:dim1(1.0)" + }, + "annotations": [], + "maxOccurs": 20, + "id": "1", + "isPresentational": true + } + ] + } + ], + "id": "1" + } + }, + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "description": "Some artefact", + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "agencyID": "IMF", + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=IMF:ARTEFACT(1.2)", + "rel": "self", + "type": "metadatastructure" + } + ], + "id": "ARTEFACT", + "validFrom": "2022-07-17T10:11:16.000000", + "version": "1.2", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000" + } + ], + "representationMaps": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)", + "type": "representationmap", + "rel": "self" + } + ], + "source": [ + { + "codelist": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:SOURCE(1.5.1)" + }, + { + "dataType": "DateTime" + } + ], + "target": [ + { + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_SOURCE(1.0)" + } + ], + "representationMappings": [ + { + "annotations": [], + "validTo": "2022-07-17T00:00:00.000Z", + "validFrom": "2022-07-17T00:00:00.000Z", + "sourceValues": [ + { + "value": "mappedValue", + "isRegEx": true, + "startIndex": 0, + "endIndex": 10 + } + ], + "targetValues": [ + "targetValue1", + "targetValue2" + ] + } + ] + } + ], + "dataflows": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=IMF:ARTEFACT(1.2)", + "type": "dataflow", + "rel": "self" + } + ], + "structure": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)" + } + ] + }, + "meta": { + "schema": "https://raw.githubusercontent.com/sdmx-twg/sdmx-json/master/metadata-message/tools/schemas/2.0.0/sdmx-json-metadata-schema.json", + "id": "IDREF8124", + "test": false, + "prepared": "2021-11-02T09:47:41.000000", + "contentLanguages": [ + "en" + ], + "sender": { + "id": "unknown" + } + } +} diff --git a/sdmx-json10/src/test/resources/deserialization.expected/test.json b/sdmx-json10/src/test/resources/deserialization.expected/test.json new file mode 100644 index 0000000..135d5a7 --- /dev/null +++ b/sdmx-json10/src/test/resources/deserialization.expected/test.json @@ -0,0 +1,147 @@ +{ + "dataStructureComponents": { + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [], + "attributes": [ + { + "annotations": [], + "id": "COMMENT", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=QUANTHUB:ECOFIN_CONCEPTS(1.0).COMMENT", + "isMandatory": false, + "conceptRoles": [], + "attributeRelationship": { + "none": {} + } + }, + { + "annotations": [], + "id": "BASE_PER", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=SDMX:CROSS_DOMAIN_CONCEPTS(1.0).BASE_PER", + "isMandatory": false, + "conceptRoles": [], + "attributeRelationship": { + "dimensions": [ + "DATA_DOMAIN", + "REF_AREA", + "INDICATOR", + "COUNTERPART_AREA", + "FREQ" + ] + } + }, + { + "annotations": [], + "id": "UNIT_MULT", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=SDMX:CROSS_DOMAIN_CONCEPTS(1.0).UNIT_MULT", + "isMandatory": false, + "conceptRoles": [], + "attributeRelationship": { + "dimensions": [ + "DATA_DOMAIN", + "REF_AREA", + "INDICATOR", + "COUNTERPART_AREA", + "FREQ" + ] + } + }, + { + "annotations": [], + "id": "OBS_STATUS", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=SDMX:CROSS_DOMAIN_CONCEPTS(1.0).OBS_STATUS", + "isMandatory": false, + "conceptRoles": [], + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "id": "TIME_FORMAT", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=SDMX:CROSS_DOMAIN_CONCEPTS(1.0).TIME_FORMAT", + "isMandatory": false, + "conceptRoles": [], + "attributeRelationship": { + "dimensions": [ + "DATA_DOMAIN", + "REF_AREA", + "INDICATOR", + "COUNTERPART_AREA", + "FREQ" + ] + } + } + ] + }, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "annotations": [], + "id": "DATA_DOMAIN", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=QUANTHUB:ECOFIN_CONCEPTS(1.0).DATA_DOMAIN", + "position": 0, + "type": "Dimension", + "conceptRoles": [] + }, + { + "annotations": [], + "id": "REF_AREA", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=QUANTHUB:ECOFIN_CONCEPTS(2.0.0-draft).REF_AREA", + "position": 1, + "type": "Dimension", + "conceptRoles": [] + }, + { + "annotations": [], + "id": "INDICATOR", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=QUANTHUB:ECOFIN_CONCEPTS(1.0).INDICATOR", + "position": 2, + "type": "Dimension", + "conceptRoles": [] + }, + { + "annotations": [], + "id": "COUNTERPART_AREA", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=QUANTHUB:ECOFIN_CONCEPTS(1.0).COUNTERPART_AREA", + "position": 3, + "type": "Dimension", + "conceptRoles": [] + }, + { + "annotations": [], + "id": "FREQ", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=SDMX:CROSS_DOMAIN_CONCEPTS(1.0).FREQ", + "position": 4, + "type": "Dimension", + "conceptRoles": [] + } + ], + "timeDimensions": [ + { + "annotations": [], + "id": "TIME_PERIOD", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=SDMX:CROSS_DOMAIN_CONCEPTS(1.0).TIME_PERIOD", + "position": 5, + "type": "TimeDimension" + } + ] + }, + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "OBS_VALUE", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=SDMX:CROSS_DOMAIN_CONCEPTS(1.0).OBS_VALUE", + "isMandatory": false, + "conceptRoles": [] + } + ] + } + } +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/agency-scheme.json b/sdmx-json10/src/test/resources/serialization.expected/agency-scheme.json new file mode 100644 index 0000000..2b8685a --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/agency-scheme.json @@ -0,0 +1,148 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.base.AgencyScheme=SDMX:AGENCIES(1.0)", + "type": "agencyscheme", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "AGENCIES", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.0", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "SDMX", + "isPartial": false, + "isFinal": true, + "agencies": [ + { + "annotations": [ + { + "id": "Annot" + } + ], + "id": "AG-1", + "name": "Agency", + "names": { + "en": "Agency" + }, + "description": "Agency", + "descriptions": { + "en": "Agency" + }, + "contacts": [ + { + "name": "AG_1", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + }, + { + "name": "AG_2", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax2" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + } + ] + }, + { + "id": "AG-2", + "name": "Agency", + "names": { + "en": "Agency" + }, + "description": "Agency", + "descriptions": { + "en": "Agency" + }, + "contacts": [ + { + "name": "AG_1", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + }, + { + "name": "AG_2", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax2" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/attribute-list.json b/sdmx-json10/src/test/resources/serialization.expected/attribute-list.json new file mode 100644 index 0000000..efaac68 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/attribute-list.json @@ -0,0 +1,26 @@ +{ + "attributeList": { + "id": "AttributeDescriptor", + "attributes": [ + { + "id": "DA1", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "localRepresentation": { + "textFormat": { + "textType": "AlphaNumeric" + } + }, + "assignmentStatus": "Conditional", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "dimensions": [ + "DIM1" + ] + } + } + ] + } +} diff --git a/sdmx-json10/src/test/resources/serialization.expected/attribute-list_empty.json b/sdmx-json10/src/test/resources/serialization.expected/attribute-list_empty.json new file mode 100644 index 0000000..c618b3a --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/attribute-list_empty.json @@ -0,0 +1,3 @@ +{ + "attributeList": null +} diff --git a/sdmx-json10/src/test/resources/serialization.expected/categorisation.json b/sdmx-json10/src/test/resources/serialization.expected/categorisation.json new file mode 100644 index 0000000..0df21d1 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/categorisation.json @@ -0,0 +1,36 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Categorisation=IMF:ARTEFACT(1.2)", + "type": "categorisation", + "rel": "self" + } + ], + "source": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Categorisation=IMF:ARTEFACT(1.2)", + "target": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Category=IMF:ARTEFACT(1.2).CAT_TARGET", + "isFinal": true +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/category-schema.json b/sdmx-json10/src/test/resources/serialization.expected/category-schema.json new file mode 100644 index 0000000..b8fd488 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/category-schema.json @@ -0,0 +1,92 @@ +{ + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "type": "type1" + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16Z", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "isPartial": true, + "isFinal": true, + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:ARTEFACT(1.2)", + "rel": "self", + "type": "categoryscheme" + } + ], + "id": "ARTEFACT", + "categories": [ + { + "names": { + "en": "Category1" + }, + "name": "Category1", + "annotations": [ + { + "id": "Annot" + } + ], + "description": "description category 1", + "id": "Category-1", + "categories": [ + { + "names": { + "en": "Category2" + }, + "name": "Category2", + "annotations": [ + { + "id": "Annot" + }, + { + "id": "Annot2" + } + ], + "description": "description category2", + "id": "Category-2", + "descriptions": { + "en": "description category2" + } + }, + { + "names": { + "en": "Category3" + }, + "name": "Category3", + "description": "description category3", + "id": "Category-3", + "descriptions": { + "en": "description category3" + } + } + ], + "descriptions": { + "en": "description category 1" + } + }, + { + "names": { + "en": "Category4" + }, + "name": "Category4", + "id": "Category-4" + } + ], + "validTo": "2022-07-17T10:11:16Z" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/category-scheme-map.json b/sdmx-json10/src/test/resources/serialization.expected/category-scheme-map.json new file mode 100644 index 0000000..174df14 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/category-scheme-map.json @@ -0,0 +1,60 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.structuremapping.CategorySchemeMap=IMF:ARTEFACT(1.2)", + "type": "categoryschememap", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "isFinal": true, + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "itemMaps": [ + { + "annotations": [ + { + "id": "Ann" + } + ], + "sourceValue": "S-1", + "targetValue": "IM-1", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + }, + { + "annotations": [ + { + "id": "Ann" + } + ], + "sourceValue": "S-2", + "targetValue": "IM-2", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + } + ], + "source": "urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:CatScheme(1.0)", + "target": "urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:CatScheme(1.1)" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/codelist.json b/sdmx-json10/src/test/resources/serialization.expected/codelist.json new file mode 100644 index 0000000..897c17e --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/codelist.json @@ -0,0 +1,60 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "isFinal": true, + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:ARTEFACT(1.2)", + "type": "codelist", + "rel": "self" + } + ], + "isPartial": true, + "codes": [ + { + "id": "CODE1", + "name": "code 1", + "names": { + "en": "code 1" + }, + "description": "code 1 desc", + "descriptions": { + "en": "code 1 desc" + }, + "parent": "CODE2" + }, + { + "id": "CODE2", + "name": "code 2", + "names": { + "en": "code 2" + }, + "description": "code 2 desc", + "descriptions": { + "en": "code 2 desc" + } + } + ] +} diff --git a/sdmx-json10/src/test/resources/serialization.expected/concept-scheme-map.json b/sdmx-json10/src/test/resources/serialization.expected/concept-scheme-map.json new file mode 100644 index 0000000..facf609 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/concept-scheme-map.json @@ -0,0 +1,60 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.structuremapping.ConceptSchemeMap=IMF:ARTEFACT(1.2)", + "type": "conceptschememap", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "isFinal": true, + "itemMaps": [ + { + "annotations": [ + { + "id": "Ann" + } + ], + "sourceValue": "S-1", + "targetValue": "IM-1", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + }, + { + "annotations": [ + { + "id": "Ann" + } + ], + "sourceValue": "S-2", + "targetValue": "IM-2", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + } + ], + "source": "urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ConScheme(1.0)", + "target": "urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ConScheme(1.1)" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/concept-scheme.json b/sdmx-json10/src/test/resources/serialization.expected/concept-scheme.json new file mode 100644 index 0000000..355bedf --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/concept-scheme.json @@ -0,0 +1,49 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ARTEFACT(1.2)", + "type": "conceptscheme", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "concepts": [ + { + "id": "COUNTRY", + "name": "Country", + "names": { + "en": "Country" + }, + "coreRepresentation": { + "textFormat": { + "textType": "Alpha" + } + } + } + ], + "isPartial": true, + "isFinal": true +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/data-constraint.json b/sdmx-json10/src/test/resources/serialization.expected/data-constraint.json new file mode 100644 index 0000000..deef951 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/data-constraint.json @@ -0,0 +1,99 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.registry.DataConstraint=IMF:ARTEFACT(1.2)", + "type": "dataconstraint", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "isFinal": true, + "agencyID": "IMF", + "constraintAttachment": { + "dataProvider": "urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP" + }, + "role": "Allowed", + "releaseCalendar": { + "tolerance": "Tolerance", + "offset": "Offset", + "periodicity": "Periodicity" + }, + "cubeRegions": [ + { + "isIncluded": true, + "attributes": [ + { + "id": "some component id 1", + "values": [ + "selectionValue local", + "selectionValue1" + ] + }, + { + "id": "some component id 2", + "values": [ + "selectionValue2", + "selectionValue5" + ] + } + ], + "keyValues": [ + { + "id": "123", + "timeRange": { + "beforePeriod": { + "period": "2020", + "isInclusive": false + }, + "afterPeriod": { + "period": "2021", + "isInclusive": false + } + } + } + ], + "annotations": [ + { + "id": "Annot" + } + ] + } + ], + "dataKeySets": [ + { + "isIncluded": true, + "keys": [ + { + "keyValues": [ + { + "id": "C1", + "value": "Value" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/data-consumer-scheme.json b/sdmx-json10/src/test/resources/serialization.expected/data-consumer-scheme.json new file mode 100644 index 0000000..b6e90e5 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/data-consumer-scheme.json @@ -0,0 +1,90 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.base.DataConsumerScheme=IMF:DATA_CONSUMERS(1.0)", + "type": "dataconsumerscheme", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "DATA_CONSUMERS", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.0", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "isPartial": false, + "isFinal": true, + "dataConsumers": [ + { + "id": "DC", + "name": "Data Consumer", + "names": { + "en": "Data Consumer" + }, + "description": "Data Consumer description", + "descriptions": { + "en": "Data Consumer description" + }, + "contacts": [ + { + "name": "AG_1", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + }, + { + "name": "AG_2", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax2" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/data-flow.json b/sdmx-json10/src/test/resources/serialization.expected/data-flow.json new file mode 100644 index 0000000..77d29de --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/data-flow.json @@ -0,0 +1,40 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "isFinal": true, + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + }, + "links": [ + { + "uri": "http://some.com" + } + ] + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=IMF:ARTEFACT(1.2)", + "type": "dataflow", + "rel": "self" + } + ], + "structure": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/data-provider-scheme.json b/sdmx-json10/src/test/resources/serialization.expected/data-provider-scheme.json new file mode 100644 index 0000000..ebcc6b0 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/data-provider-scheme.json @@ -0,0 +1,92 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.base.DataProviderScheme=IMF:DATA_PROVIDERS(1.0)", + "type": "dataproviderscheme", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "DATA_PROVIDERS", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.0", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "isPartial": true, + "isFinal": true, + "dataProviders": [ + { + "annotations": [ + { + "id": "Ann", + "value": "Val", + } + ], + "id": "Prov", + "name": "D_P", + "names": { + "en": "D_P" + }, + "contacts": [ + { + "name": "AG_1", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + }, + { + "name": "AG_2", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax2" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/data-structure-definition-order.json b/sdmx-json10/src/test/resources/serialization.expected/data-structure-definition-order.json new file mode 100644 index 0000000..802a1c1 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/data-structure-definition-order.json @@ -0,0 +1,147 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)", + "type": "datastructure", + "rel": "self" + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "MES1", + "isMandatory": false, + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod", + "isMultiLingual": false + } + } + } + ] + }, + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [ + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-1", + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-2", + "attributeRelationship": { + "dimensions": [ + "dim1", + "dim2" + ] + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-3", + "attributeRelationship": { + "none": {} + } + } + ], + "attributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "annotations": [], + "id": "DA1", + "isMandatory": false, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "group": "GroupKey" + }, + "measureRelationship": [ + "MO" + ], + "localRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + } + ] + }, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "annotations": [], + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE" + ], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "annotations": [], + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod" + } + } + } + ] + } + } +} diff --git a/sdmx-json10/src/test/resources/serialization.expected/data-structure-definition.json b/sdmx-json10/src/test/resources/serialization.expected/data-structure-definition.json new file mode 100644 index 0000000..00fb6af --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/data-structure-definition.json @@ -0,0 +1,113 @@ +{ + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "type": "type1" + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16Z", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "dataStructureComponents": { + "groups": [ + { + "id": "GROUP1", + "groupDimensions": [ + "DIM1" + ] + } + ], + "attributeList": { + "attributes": [ + { + "assignmentStatus": "Conditional", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "attributeRelationship": { + "dimensions": [ + "DIM1" + ], + "attachmentGroups": [ + "GROUP1" + ] + }, + "localRepresentation": { + "textFormat": { + "textType": "AlphaNumeric" + } + }, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "id": "DA1" + } + ], + "id": "AttributeDescriptor" + }, + "dimensionList": { + "timeDimensions": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": { + "textFormat": { + "textType": "BasicTimePeriod" + } + }, + "id": "TIME_PERIOD", + "position": 2, + "type": "TimeDimension" + } + ], + "id": "DimensionDescriptor", + "dimensions": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + }, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE" + ], + "id": "DIM1", + "position": 1, + "type": "Dimension" + } + ] + }, + "measureList": { + "primaryMeasure": { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "localRepresentation": { + "textFormat": { + "textType": "BasicTimePeriod" + } + }, + "id": "MES1" + }, + "id": "MeasureDescriptor" + } + }, + "name": "Maintanable artefact", + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)", + "rel": "self", + "type": "datastructure" + } + ], + "id": "ARTEFACT", + "isFinal": true, + "validTo": "2022-07-17T10:11:16Z" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/dimension-list.json b/sdmx-json10/src/test/resources/serialization.expected/dimension-list.json new file mode 100644 index 0000000..1d6de29 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/dimension-list.json @@ -0,0 +1,27 @@ +{ + "dimensionList": { + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE" + ], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE" + } + ] + } +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/dimension-list_empty.json b/sdmx-json10/src/test/resources/serialization.expected/dimension-list_empty.json new file mode 100644 index 0000000..077919e --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/dimension-list_empty.json @@ -0,0 +1,3 @@ +{ + "dimensionList": null +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/empty-structure.json b/sdmx-json10/src/test/resources/serialization.expected/empty-structure.json new file mode 100644 index 0000000..bf9ef71 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/empty-structure.json @@ -0,0 +1,15 @@ +{ + "data": {}, + "meta": { + "schema": "https://raw.githubusercontent.com/sdmx-twg/sdmx-json/master/metadata-message/tools/schemas/2.0.0/sdmx-json-metadata-schema.json", + "id": "IDREF7553", + "test": false, + "prepared": "2022-04-03T15:35:01Z", + "contentLanguages": [ + "en" + ], + "sender": { + "id": "unknown" + } + } +} diff --git a/sdmx-json10/src/test/resources/serialization.expected/expected-flat-json-streamer-response.json b/sdmx-json10/src/test/resources/serialization.expected/expected-flat-json-streamer-response.json new file mode 100644 index 0000000..a7e7435 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/expected-flat-json-streamer-response.json @@ -0,0 +1,110 @@ +{ + "meta": {}, + "data": { + "dataSets": [ + { + "structure": 0, + "action": "Information", + "observations": { + "0:0": [ + "obsValue2" + ], + "0:1": [ + "obsValue5" + ], + "1:1": [ + "obsValue6" + ] + } + } + ], + "structures": [ + { + "dataSets": [ + 0 + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=QH:DF(4.20)", + "title": "Dataflow" + }, + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QH:DSD(4.20)", + "title": "DataStructureDefinition" + } + ], + "dimensions": { + "series": [ + { + "id": "dim1", + "keyPosition": 0, + "roles": [], + "values": [ + { + "value": "dim1-val1" + }, + { + "value": "dim1-val2" + } + ] + }, + { + "id": "dim2", + "keyPosition": 1, + "roles": [ + "role" + ], + "values": [ + { + "value": "dim2-val1" + }, + { + "value": "dim2-val2" + } + ] + } + ] + }, + "measures": { + "observation": [ + { + "id": "OBS_VALUE", + "roles": [] + } + ] + }, + "attributes": { + "dataSet": [ + { + "id": "dataset", + "roles": [], + "isMandatory": false, + "relationship": { + "dataflow": {} + } + } + ], + "observation": [ + { + "id": "observation1", + "roles": [], + "isMandatory": false, + "relationship": { + "observation": {} + } + }, + { + "id": "observation2", + "roles": [], + "isMandatory": false, + "relationship": { + "observation": {} + } + } + ] + }, + "annotations": [] + } + ] + } +} diff --git a/sdmx-json10/src/test/resources/serialization.expected/geocodelist.json b/sdmx-json10/src/test/resources/serialization.expected/geocodelist.json new file mode 100644 index 0000000..7ea6397 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/geocodelist.json @@ -0,0 +1,92 @@ +{ + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "geoFeatureSetCodes": [ + { + "parent": "CODE2", + "names": { + "en": "code 1" + }, + "name": "code 1", + "annotations": [], + "description": "code 1 desc", + "id": "CODE1", + "descriptions": { + "en": "code 1 desc" + }, + "value": "Value1" + }, + { + "names": { + "en": "code 2" + }, + "name": "code 2", + "annotations": [], + "description": "code 2 desc", + "id": "CODE2", + "descriptions": { + "en": "code 2 desc" + }, + "value": "Value2" + } + ], + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16Z", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "codelistExtensions": [ + { + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "prefix": "PREF2", + "inclusiveCodeSelection": { + "memberValues": [ + { + "cascadeValues": "true", + "value": "mem1" + } + ] + } + }, + { + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "prefix": "PREF2", + "exclusiveCodeSelection": { + "memberValues": [ + { + "cascadeValues": "false", + "value": "mem2" + } + ] + } + } + ], + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "geoType": "GeographicCodelist", + "name": "Maintanable artefact", + "isPartial": true, + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.codelist.GeographicCodelist=IMF:ARTEFACT(1.2)", + "rel": "self", + "type": "geographiccodelist" + } + ], + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16Z" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/geogridcodelist.json b/sdmx-json10/src/test/resources/serialization.expected/geogridcodelist.json new file mode 100644 index 0000000..bea7773 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/geogridcodelist.json @@ -0,0 +1,93 @@ +{ + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16Z", + "geoGridCodes": [ + { + "parent": "CODE2", + "names": { + "en": "code 1" + }, + "geoCell": "Value1", + "name": "code 1", + "annotations": [], + "description": "code 1 desc", + "id": "CODE1", + "descriptions": { + "en": "code 1 desc" + } + }, + { + "names": { + "en": "code 2" + }, + "geoCell": "Value2", + "name": "code 2", + "annotations": [], + "description": "code 2 desc", + "id": "CODE2", + "descriptions": { + "en": "code 2 desc" + } + } + ], + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "codelistExtensions": [ + { + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "prefix": "PREF2", + "inclusiveCodeSelection": { + "memberValues": [ + { + "cascadeValues": "true", + "value": "mem1" + } + ] + } + }, + { + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "prefix": "PREF2", + "exclusiveCodeSelection": { + "memberValues": [ + { + "cascadeValues": "false", + "value": "mem2" + } + ] + } + } + ], + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "geoType": "GeoGridCodelist", + "name": "Maintanable artefact", + "isPartial": true, + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.codelist.GeoGridCodelist=IMF:ARTEFACT(1.2)", + "rel": "self", + "type": "geogridcodelist" + } + ], + "id": "ARTEFACT", + "gridDefinition": "DEFINITION", + "validTo": "2022-07-17T10:11:16Z" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/group-dimension-list.json b/sdmx-json10/src/test/resources/serialization.expected/group-dimension-list.json new file mode 100644 index 0000000..369d450 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/group-dimension-list.json @@ -0,0 +1,26 @@ +{ + "groups": [ + { + "annotations": [ + { + "id": "id1" + }, + { + "id": "id2" + } + ], + "id": "GroupDimensionDescriptor1", + "groupDimensions": [ + "dim1", + "dim12" + ] + }, + { + "id": "GroupDimensionDescriptor2", + "groupDimensions": [ + "dim21", + "dim22" + ] + } + ] +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/hierarchy.json b/sdmx-json10/src/test/resources/serialization.expected/hierarchy.json new file mode 100644 index 0000000..6398467 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/hierarchy.json @@ -0,0 +1,87 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.codelist.Hierarchy=IMF:ARTEFACT(1.2)", + "type": "hierarchy", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "isFinal": true, + "agencyID": "IMF", + "hierarchies": [ + { + "id": "Hierarchy", + "name": "Hierarchy", + "hierarchicalCodes": [ + { + "annotations": [ + { + "id": "id" + } + ], + "id": "id", + "validFrom": "2022-07-17T10:11:16.345Z", + "validTo": "2022-07-17T10:11:16.345Z", + "code": "urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1", + "codeID": "CL1", + "level": "Lev1", + "hierarchicalCodes": [ + { + "id": "1", + "validFrom": "2022-07-17T10:11:16.345Z", + "validTo": "2022-07-17T10:11:16.345Z", + "code": "urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1", + "codeID": "CL1", + "level": null + } + ] + } + ] + } + ], + "level": { + "id": "levId", + "name": "hierarchy name", + "names": { + "en": "hierarchy name" + }, + "description": "hierarchy desc", + "descriptions": { + "en": "hierarchy desc" + }, + "codingFormat": { + "interval": 1 + }, + "level": { + "id": "levUn", + "name": "underLevel", + "names": { + "en": "underLevel" + }, + "codingFormat": {} + } + } +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/hierarchy_flat.json b/sdmx-json10/src/test/resources/serialization.expected/hierarchy_flat.json new file mode 100644 index 0000000..544dc15 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/hierarchy_flat.json @@ -0,0 +1,77 @@ +{ + "hierarchies": [ + { + "name": "Hierarchy", + "hierarchicalCodes": [ + { + "codeID": "CL1", + "code": "urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1", + "level": "Lev1", + "annotations": [ + { + "id": "id" + } + ], + "id": "id", + "validFrom": "2022-07-17T10:11:16.345Z", + "validTo": "2022-07-17T10:11:16.345Z" + }, + { + "codeID": "CL2", + "code": "urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL2", + "level": "Lev2", + "id": "hi-2", + "validFrom": "2022-07-17T10:11:16.345Z", + "validTo": "2022-07-17T10:11:16.345Z" + } + ], + "id": "Hierarchy" + } + ], + "level": { + "names": { + "en": "hierarchy name" + }, + "codingFormat": { + "interval": 1 + }, + "name": "hierarchy name", + "description": "hierarchy desc", + "id": "levId", + "descriptions": { + "en": "hierarchy desc" + } + }, + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "type": "type1" + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16Z", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.codelist.Hierarchy=IMF:ARTEFACT(1.2)", + "rel": "self", + "type": "hierarchy" + } + ], + "id": "ARTEFACT", + "isFinal": true, + "validTo": "2022-07-17T10:11:16Z" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/measure-list.json b/sdmx-json10/src/test/resources/serialization.expected/measure-list.json new file mode 100644 index 0000000..f56bf05 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/measure-list.json @@ -0,0 +1,14 @@ +{ + "measureList": { + "id": "MeasureDescriptor", + "primaryMeasure": { + "id": "MES1", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "localRepresentation": { + "textFormat": { + "textType": "BasicTimePeriod" + } + } + } + } +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/measure-list_empty.json b/sdmx-json10/src/test/resources/serialization.expected/measure-list_empty.json new file mode 100644 index 0000000..679b765 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/measure-list_empty.json @@ -0,0 +1,3 @@ +{ + "measureList": null +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/meta-data-constraint.json b/sdmx-json10/src/test/resources/serialization.expected/meta-data-constraint.json new file mode 100644 index 0000000..ce5dcd3 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/meta-data-constraint.json @@ -0,0 +1,69 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.registry.MetadataConstraint=IMF:ARTEFACT(1.2)", + "type": "metadataconstraint", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "isFinal": true, + "agencyID": "IMF", + "constraintAttachment": { + "dataProvider": "urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP", + "metadataStructures": [ + "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)" + ] + }, + "role": "Allowed", + "releaseCalendar": { + "tolerance": "Tolerance", + "offset": "Offset", + "periodicity": "Periodicity" + }, + "metadataTargetRegions": [ + { + "include": true, + "attributes": [ + { + "id": "MS", + "values": [ + "MEM", + "local" + ] + }, + { + "id": "MS2", + "timeRange": { + "beforePeriod": { + "period": "2023", + "isInclusive": true + } + } + } + ] + } + ] +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/metadata-constraint.json b/sdmx-json10/src/test/resources/serialization.expected/metadata-constraint.json new file mode 100644 index 0000000..de408c2 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/metadata-constraint.json @@ -0,0 +1,77 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.registry.MetadataConstraint=IMF:ARTEFACT(1.2)", + "type": "metadataconstraint", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "role": "Allowed", + "metadataTargetRegions": [ + { + "include": true, + "validFrom": "2022-07-17T10:11:16Z", + "validTo": "2022-07-17T10:11:16Z", + "components": [ + { + "include": false, + "id": "MS", + "removePrefix": true, + "values": [ + { + "value": "MEM", + "cascadeValues": "excluderoot", + "validFrom": "2022-07-17T10:11:16Z", + "validTo": "2022-09-17T10:11:16Z" + } + ] + }, + { + "include": false, + "id": "MS2", + "removePrefix": true, + "timeRange": { + "beforePeriod": { + "period": "2023", + "isInclusive": true + } + } + } + ] + } + ], + "releaseCalendar": { + "tolerance": "Tolerance", + "offset": "Offset", + "periodicity": "Periodicity" + }, + "constraintAttachment": { + "metadataProvider": "urn:sdmx:org.sdmx.infomodel.base.MetadataProvider=IMF:METADATA_PROVIDERS(1.0).PR" + } +} diff --git a/sdmx-json10/src/test/resources/serialization.expected/metadata-flow.json b/sdmx-json10/src/test/resources/serialization.expected/metadata-flow.json new file mode 100644 index 0000000..231de6d --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/metadata-flow.json @@ -0,0 +1,39 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=IMF:ARTEFACT(1.2)", + "type": "metadataflow", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "isFinal": true, + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "structure": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=IMF:METADATA(1.0.0)", + "targets": [ + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.3)" + ] +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/metadata-provider-scheme.json b/sdmx-json10/src/test/resources/serialization.expected/metadata-provider-scheme.json new file mode 100644 index 0000000..8a5a31d --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/metadata-provider-scheme.json @@ -0,0 +1,96 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.base.MetadataProviderScheme=IMF:METADATA_PROVIDERS(1.0)", + "type": "metadataproviderscheme", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "METADATA_PROVIDERS", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.0", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "isPartial": true, + "metadataProviders": [ + { + "annotations": [ + { + "id": "Ann", + "title": null, + "type": null, + "value": "Val", + "text": null + } + ], + "id": "Prov", + "name": "MD_P", + "names": { + "en": "MD_P" + }, + "contacts": [ + { + "name": "AG_1", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + }, + { + "name": "AG_2", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax2" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/metadata-provision-agreement.json b/sdmx-json10/src/test/resources/serialization.expected/metadata-provision-agreement.json new file mode 100644 index 0000000..a886681 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/metadata-provision-agreement.json @@ -0,0 +1,37 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.registry.MetadataProvisionAgreement=IMF:ARTEFACT(1.2)", + "type": "metadataprovisionagreement", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "metadataProvider": "urn:sdmx:org.sdmx.infomodel.base.MetadataProvider=IMF:METADATA_PROVIDERS(1.0).PR", + "metadataflow": "urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=IMF:ARTEFACT(1.2)" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/metadata-structure-definition.json b/sdmx-json10/src/test/resources/serialization.expected/metadata-structure-definition.json new file mode 100644 index 0000000..aaddb21 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/metadata-structure-definition.json @@ -0,0 +1,68 @@ +{ + "metadataStructureComponents": { + "metadataAttributeList": { + "annotations": [ + { + "id": "Annot-1" + } + ], + "metadataAttributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DIM", + "minOccurs": 10, + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + }, + "maxOccurs": 20, + "metadataAttributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DIM", + "minOccurs": 10, + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + }, + "maxOccurs": 20, + "id": "meta-2", + "isPresentational": true + } + ], + "id": "meta-1", + "isPresentational": true + } + ], + "id": "MetadataAttributeDescriptor" + } + }, + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "type": "type1" + } + ], + "description": "Some artefact", + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=IMF:ARTEFACT(1.2)", + "rel": "self", + "type": "metadatastructure" + } + ], + "agencyID": "IMF", + "id": "ARTEFACT", + "validFrom": "2022-07-17T10:11:16Z", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "isFinal": true +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/metadata.json b/sdmx-json10/src/test/resources/serialization.expected/metadata.json new file mode 100644 index 0000000..2c50209 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/metadata.json @@ -0,0 +1,75 @@ +{ + "data": { + "metadataSets": [ + { + "metadataflow": "urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=EPM:MetadataSet(1.8)", + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "reportingEnd": "2022", + "validFrom": "2022-07-17T10:11:16Z", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "targets": [ + "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataSet=EPM:MetadataSetTar(1.8)" + ], + "reportingBegin": "2022", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "publicationPeriod": "2022-03", + "publicationYear": "2022", + "action": "Append", + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataSet=IMF:ARTEFACT(1.2)", + "rel": "self", + "type": "metadataset" + } + ], + "attributes": [ + { + "id": "attr1", + "value": "someVal", + "attributes": [ + { + "attributes": [], + "id": "attr2", + "value": "someVal2" + } + ] + } + ], + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16Z" + } + ] + }, + "meta": { + "schema": "https://raw.githubusercontent.com/sdmx-twg/sdmx-json/master/metadata-message/tools/schemas/2.0.0/sdmx-json-metadata-schema.json", + "id": "IDREF8124", + "test": false, + "prepared": "2021-11-02T09:47:41Z", + "contentLanguages": [ + "en" + ], + "sender": { + "id": "unknown" + } + } +} diff --git a/sdmx-json10/src/test/resources/serialization.expected/metadataset.json b/sdmx-json10/src/test/resources/serialization.expected/metadataset.json new file mode 100644 index 0000000..7db25c2 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/metadataset.json @@ -0,0 +1,56 @@ +{ + "metadataflow": "urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=EPM:MetadataSet(1.8)", + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "reportingEnd": "2022", + "validFrom": "2022-07-17T10:11:16Z", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "targets": [ + "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataSet=EPM:MetadataSetTar(1.8)" + ], + "reportingBegin": "2022", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "publicationPeriod": "2022-03", + "publicationYear": "2022", + "action": "Append", + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataSet=IMF:ARTEFACT(1.2)", + "rel": "self", + "type": "metadataset" + } + ], + "attributes": [ + { + "id": "attr1", + "value": "someVal", + "attributes": [ + { + "id": "attr2", + "value": "someVal2" + } + ] + } + ], + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16Z" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/organisation-scheme-map.json b/sdmx-json10/src/test/resources/serialization.expected/organisation-scheme-map.json new file mode 100644 index 0000000..a9dc749 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/organisation-scheme-map.json @@ -0,0 +1,60 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.structuremapping.OrganisationSchemeMap=IMF:ARTEFACT(1.2)", + "type": "organisationschememap", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "isFinal": true, + "itemMaps": [ + { + "annotations": [ + { + "id": "Ann" + } + ], + "sourceValue": "S-1", + "targetValue": "IM-1", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + }, + { + "annotations": [ + { + "id": "Ann" + } + ], + "sourceValue": "S-2", + "targetValue": "IM-2", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + } + ], + "source": "urn:sdmx:org.sdmx.infomodel.base.AgencyScheme=SDMX:AGENCIES(1.0)", + "target": "urn:sdmx:org.sdmx.infomodel.base.AgencyScheme=SDMX:AGENCIES(1.0)" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/organisation-unit-scheme.json b/sdmx-json10/src/test/resources/serialization.expected/organisation-unit-scheme.json new file mode 100644 index 0000000..b8dd3c3 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/organisation-unit-scheme.json @@ -0,0 +1,103 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.base.OrganisationUnitScheme=IMF:ARTEFACT(1.0)", + "type": "organisationunitscheme", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.0", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "isPartial": true, + "isFinal": true, + "organisationUnits": [ + { + "annotations": [ + { + "id": "Annot" + } + ], + "id": "OrgUnit", + "name": "OrganisationUnit", + "names": { + "en": "OrganisationUnit" + }, + "description": "OrganisationUnit description", + "descriptions": { + "en": "OrganisationUnit description" + }, + "contacts": [ + { + "name": "AG_1", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + }, + { + "name": "AG_2", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax2" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + } + ] + }, + { + "id": "OrgUnit2", + "parent": "OrgUnit", + "name": "OrganisationUnit", + "names": { + "en": "OrganisationUnit" + } + } + ] +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/process.json b/sdmx-json10/src/test/resources/serialization.expected/process.json new file mode 100644 index 0000000..b89fe09 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/process.json @@ -0,0 +1,136 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.process.Process=IMF:ARTEFACT(1.2)", + "type": "process", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "processSteps": [ + { + "annotations": [ + { + "id": "Annot", + "title": null, + "type": null, + "value": null, + "text": null + } + ], + "id": "ProcStep", + "name": "ProcessStep", + "names": { + "en": "ProcessStep" + }, + "description": "ProcessStep description", + "descriptions": { + "en": "ProcessStep description" + }, + "computation": { + "localID": "LocId", + "softwareLanguage": "SoftwareLanguage", + "softwarePackage": "SoftwarePackage", + "softwareVersion": "SoftwareVersion", + "annotations": [ + { + "id": "Annot", + "title": null, + "type": null, + "value": null, + "text": null + } + ], + "description": "Computation Description", + "descriptions": { + "en": "Computation Description" + } + }, + "transitions": [ + { + "annotations": [], + "id": "Trans", + "localID": "Loc", + "condition": "Doo", + "conditions": { + "en": "Doo" + }, + "targetStep": "ST" + } + ], + "outputs": [ + { + "localID": "Loc", + "annotations": [ + { + "id": "Annot", + "title": null, + "type": null, + "value": null, + "text": null + } + ], + "objectReference": "urn:sdmx:org.sdmx.infomodel.process.ProcessStep=IMF:Artefact(1.0)" + } + ], + "inputs": [ + { + "localID": "Loc", + "annotations": [ + { + "id": "Annot", + "title": null, + "type": null, + "value": null, + "text": null + } + ], + "objectReference": "urn:sdmx:org.sdmx.infomodel.process.ProcessStep=IMF:Artefact(1.0)" + } + ], + "processSteps": [ + { + "annotations": [ + { + "id": "Annot", + "title": null, + "type": null, + "value": null, + "text": null + } + ], + "id": "ProcessChild", + "name": "ProcessStepChild", + "names": { + "en": "ProcessStepChild" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/provision-agreement.json b/sdmx-json10/src/test/resources/serialization.expected/provision-agreement.json new file mode 100644 index 0000000..9f308f4 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/provision-agreement.json @@ -0,0 +1,37 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.registry.ProvisionAgreement=IMF:ARTEFACT(1.2)", + "type": "provisionagreement", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "dataProvider": "urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP", + "dataflow": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=IMF:ARTEFACT(1.2)" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/reporting-taxonomy-map.json b/sdmx-json10/src/test/resources/serialization.expected/reporting-taxonomy-map.json new file mode 100644 index 0000000..dc4d0fa --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/reporting-taxonomy-map.json @@ -0,0 +1,69 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.structuremapping.ReportingTaxonomyMap=IMF:ARTEFACT(1.2)", + "type": "reportingtaxonomymap", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "itemMaps": [ + { + "annotations": [ + { + "id": "Ann", + "title": null, + "type": null, + "value": null, + "text": null + } + ], + "sourceValue": "S-1", + "targetValue": "IM-1", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + }, + { + "annotations": [ + { + "id": "Ann", + "title": null, + "type": null, + "value": null, + "text": null + } + ], + "sourceValue": "S-2", + "targetValue": "IM-2", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + } + ], + "source": "urn:sdmx:org.sdmx.infomodel.categoryscheme.ReportingTaxonomy=SDMX:REP_SOURCE(1.0)", + "target": "urn:sdmx:org.sdmx.infomodel.categoryscheme.ReportingTaxonomy=SDMX:REP_TARGET(1.0)" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/reporting-taxonomy.json b/sdmx-json10/src/test/resources/serialization.expected/reporting-taxonomy.json new file mode 100644 index 0000000..9dda79c --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/reporting-taxonomy.json @@ -0,0 +1,88 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.categoryscheme.ReportingTaxonomy=IMF:ARTEFACT(1.2)", + "type": "reportingtaxonomy", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "isPartial": false, + "reportingCategories": [ + { + "annotations": [ + { + "id": "Annot", + "title": null, + "type": null, + "value": null, + "text": null + } + ], + "id": "RC-1", + "name": "ReportingCat", + "names": { + "en": "ReportingCat" + }, + "description": "ReportingCat description", + "descriptions": { + "en": "ReportingCat description" + }, + "provisioningMetadata": [ + "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataS2(3.0)", + "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataS1(3.0)" + ], + "reportingCategories": [ + { + "annotations": [ + { + "id": "Annot", + "title": null, + "type": null, + "value": null, + "text": null + } + ], + "id": "RC-2", + "name": "ReportingCat2", + "names": { + "en": "ReportingCat2" + }, + "description": "ReportingCat2 description", + "descriptions": { + "en": "ReportingCat2 description" + }, + "structuralMetadata": [ + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=EPM:DataS2(3.0)", + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=EPM:DataS1(3.0)" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/representation-map.json b/sdmx-json10/src/test/resources/serialization.expected/representation-map.json new file mode 100644 index 0000000..ce6f779 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/representation-map.json @@ -0,0 +1,67 @@ +{ + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16Z", + "source": [ + { + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_SOURCE(1.0)" + }, + { + "dataType": "DateTime" + } + ], + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "target": [ + { + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_TARGET(1.0)" + } + ], + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "representationMappings": [ + { + "targetValues": [ + "targetValue1", + "targetValue2" + ], + "sourceValues": [ + { + "startIndex": 0, + "isRegEx": true, + "endIndex": 10, + "value": "mappedValue" + } + ], + "annotations": [], + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + } + ], + "name": "Maintanable artefact", + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)", + "rel": "self", + "type": "representationmap" + } + ], + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16Z" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/structure-map-with-null-map.json b/sdmx-json10/src/test/resources/serialization.expected/structure-map-with-null-map.json new file mode 100644 index 0000000..423c13f --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/structure-map-with-null-map.json @@ -0,0 +1,65 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.structuremapping.StructureMap=IMF:ARTEFACT(1.2)", + "type": "structuremap", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "epochMaps": [], + "datePatternMaps": [], + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_3", + "datePattern": "2022-11", + "annotations": [], + "id": "FR3" + }, + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "annotations": [], + "id": "FR1" + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "annotations": [], + "id": "FR2" + } + ], + "fixedValueMaps": [ + { + "annotations": [], + "value": "value" + } + ] +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/structure-map-with-null-target-source.json b/sdmx-json10/src/test/resources/serialization.expected/structure-map-with-null-target-source.json new file mode 100644 index 0000000..ac6343f --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/structure-map-with-null-target-source.json @@ -0,0 +1,120 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.structuremapping.StructureMap=IMF:ARTEFACT(1.2)", + "type": "structuremap", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "epochMaps": [ + { + "annotations": [], + "id": "EPOCH1", + "mappedComponents": [ + { + "source": "CompMapEpochS", + "target": "CompMapEpochT" + } + ], + "resolvePeriod": "MID_PERIOD", + "frequencyDimension": "Frequency_dim", + "mappedFrequencies": [ + "FR3" + ], + "yearStart": {}, + "basePeriod": "2022-07-17T10:11:16Z", + "epochPeriod": "MICROSECOND" + } + ], + "datePatternMaps": [ + { + "annotations": [], + "id": "DP1", + "mappedComponents": [ + { + "source": "CompMapDPS", + "target": "CompMapDPT" + } + ], + "resolvePeriod": "MID_PERIOD", + "frequencyDimension": "Frequency_dim", + "mappedFrequencies": [ + "FR1", + "FR2" + ], + "yearStart": {}, + "locale": "EN", + "sourcePattern": "SOURCE" + } + ], + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_3", + "datePattern": "2022-11", + "annotations": [], + "id": "FR3" + }, + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "annotations": [], + "id": "FR1" + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "annotations": [], + "id": "FR2" + } + ], + "componentMaps": [ + { + "annotations": [], + "source": [ + "CompMapRepS" + ], + "target": [ + "CompMapRepT" + ], + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)" + }, + { + "annotations": [], + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)" + } + ], + "fixedValueMaps": [ + { + "annotations": [], + "value": "value" + } + ] +} diff --git a/sdmx-json10/src/test/resources/serialization.expected/structure-map.json b/sdmx-json10/src/test/resources/serialization.expected/structure-map.json new file mode 100644 index 0000000..6203edc --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/structure-map.json @@ -0,0 +1,116 @@ +{ + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_3", + "datePattern": "2022-11", + "annotations": [], + "id": "FR3" + }, + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "annotations": [], + "id": "FR1" + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "annotations": [], + "id": "FR2" + } + ], + "datePatternMaps": [ + { + "mappedFrequencies": [ + "FR1", + "FR2" + ], + "mappedComponents": [ + { + "source": "CompMapDPS", + "target": "CompMapDPT" + } + ], + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "DP1", + "locale": "EN", + "frequencyDimension": "Frequency_dim", + "yearStart": {}, + "sourcePattern": "SOURCE" + } + ], + "fixedValueMaps": [ + { + "annotations": [], + "value": "value" + } + ], + "epochMaps": [ + { + "mappedFrequencies": [ + "FR3" + ], + "basePeriod": "2022-07-17T10:11:16Z", + "mappedComponents": [ + { + "source": "CompMapEpochS", + "target": "CompMapEpochT" + } + ], + "epochPeriod": "MICROSECOND", + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "EPOCH1", + "frequencyDimension": "Frequency_dim", + "yearStart": {} + } + ], + "componentMaps": [ + { + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)", + "annotations": [], + "source": [ + "CompMapRepS" + ], + "target": [ + "CompMapRepT" + ] + } + ], + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16Z", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.structuremapping.StructureMap=IMF:ARTEFACT(1.2)", + "rel": "self", + "type": "structuremap" + } + ], + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16Z" +} \ No newline at end of file diff --git a/sdmx-json10/src/test/resources/serialization.expected/structure.json b/sdmx-json10/src/test/resources/serialization.expected/structure.json new file mode 100644 index 0000000..b502b8c --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/structure.json @@ -0,0 +1,148 @@ +{ + "data": { + "categorisations": [ + { + "description": "categ", + "agencyID": "EPM", + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Categorisation=EPM:catid(1.0)", + "rel": "self", + "type": "categorisation" + } + ], + "id": "catid", + "source": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Categorisation=IMF:ARTEFACT(1.2).CAT_SOURCE", + "descriptions": { + "en": "categ" + }, + "version": "1.0", + "isFinal": true, + "target": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Category=IMF:ARTEFACT(1.2).CAT_TARGET" + } + ], + "dataStructures": [ + { + "dataStructureComponents": null, + "agencyID": null, + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=null:DSD1(1.0)", + "rel": "self", + "type": "datastructure" + } + ], + "id": "DSD1", + "version": "1.0", + "isFinal": true + } + ], + "hierarchicalCodelists": [ + { + "agencyID": null, + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.codelist.Hierarchy=null:Hi1(1.0)", + "rel": "self", + "type": "hierarchy" + } + ], + "id": "Hi1", + "version": "1.0", + "isFinal": true + } + ], + "categorySchemes": [ + { + "isPartial": false, + "agencyID": null, + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=null:CS1(1.0)", + "rel": "self", + "type": "categoryscheme" + } + ], + "id": "CS1", + "categories": [], + "version": "1.0", + "isFinal": true + } + ], + "codelists": [ + { + "isPartial": false, + "agencyID": null, + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=null:CL1(1.0)", + "rel": "self", + "type": "codelist" + } + ], + "id": "CL1", + "version": "1.0", + "isFinal": true + } + ], + "conceptSchemes": [ + { + "concepts": [], + "isPartial": false, + "agencyID": null, + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=null:CS1(1.0)", + "rel": "self", + "type": "conceptscheme" + } + ], + "id": "CS1", + "version": "1.0", + "isFinal": true + }, + { + "concepts": [], + "isPartial": false, + "agencyID": null, + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=null:CS2(1.0)", + "rel": "self", + "type": "conceptscheme" + } + ], + "id": "CS2", + "version": "1.0", + "isFinal": true + } + ], + "dataflows": [ + { + "agencyID": null, + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=null:DF1(1.0)", + "rel": "self", + "type": "dataflow" + } + ], + "id": "DF1", + "version": "1.0", + "isFinal": true + } + ] + }, + "meta": { + "schema": "https://raw.githubusercontent.com/sdmx-twg/sdmx-json/master/metadata-message/tools/schemas/2.0.0/sdmx-json-metadata-schema.json", + "test": false, + "sender": { + "id": "unknown" + }, + "prepared": "2022-04-03T15:35:01Z", + "contentLanguages": [ + "en" + ], + "id": "IDREF7553" + } +} diff --git a/sdmx-json10/src/test/resources/serialization.expected/valuelist.json b/sdmx-json10/src/test/resources/serialization.expected/valuelist.json new file mode 100644 index 0000000..2c261a3 --- /dev/null +++ b/sdmx-json10/src/test/resources/serialization.expected/valuelist.json @@ -0,0 +1,79 @@ +{ + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.codelist.ValueList=IMF:ARTEFACT(1.2)", + "type": "valuelist", + "rel": "self" + } + ], + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "valueItems": [ + { + "annotations": [ + { + "id": "Annot", + "title": null, + "type": null, + "value": null, + "text": null + } + ], + "id": "VAL-1", + "name": "Maintanable artefact", + "names": { + "en": "value", + "fr": "val" + }, + "description": "it is value", + "descriptions": { + "en": "it is value", + "fr": "c'est val" + } + }, + { + "annotations": [ + { + "id": "Annot", + "title": null, + "type": null, + "value": null, + "text": null + } + ], + "id": "VAL-2", + "name": "Maintanable artefact", + "names": { + "en": "smth" + }, + "description": "smth description", + "descriptions": { + "en": "smth description" + } + } + ] +} \ No newline at end of file diff --git a/sdmx-json20/build.gradle b/sdmx-json20/build.gradle new file mode 100644 index 0000000..4941ebe --- /dev/null +++ b/sdmx-json20/build.gradle @@ -0,0 +1,47 @@ +plugins { + id 'java' +} + +repositories { + mavenCentral() +} + +dependencies { + implementation project(":sdmx30-serializer") + + annotationProcessor("org.projectlombok:lombok:${lombok_version}") + compileOnly("org.projectlombok:lombok:${lombok_version}") + + implementation project(":sdmx30-infomodel") + + implementation("org.apache.logging.log4j:log4j-slf4j2-impl:${log4j_version}") + implementation("org.apache.logging.log4j:log4j-core:${log4j_version}") + implementation("com.epam.deltix:SdmxDataParser:${sdmx_version}") + + implementation("org.mapstruct:mapstruct:${mapstruct_version}") + annotationProcessor("org.mapstruct:mapstruct-processor:${mapstruct_version}") + + implementation("org.apache.commons:commons-collections4:${org_apache_commons_commons_collections4_version}") + implementation("org.apache.commons:commons-lang3:${org_apache_commons_commons_lang3_version}") + implementation("com.fasterxml.jackson.core:jackson-core:${fasterxml_version}") + implementation("com.fasterxml.jackson.core:jackson-databind:${fasterxml_databind_version}") + implementation("com.google.guava:guava:${guava_version}") + implementation "com.opencsv:opencsv:${openc_csv_version}" + + testImplementation("org.projectlombok:lombok:${lombok_version}") + testAnnotationProcessor("org.projectlombok:lombok:${lombok_version}") + + testImplementation("org.jsonschema2pojo:jsonschema2pojo-core:${jsonschema2pojo_version}") + testImplementation("io.github.benas:random-beans:${random_beans_version}") + testImplementation("org.assertj:assertj-core:${assertj_version}") + testImplementation("net.javacrumbs.json-unit:json-unit:${json_unit_version}") + testImplementation("net.javacrumbs.json-unit:json-unit-assertj:${json_unit_version}") + testImplementation("org.mockito:mockito-core:${mockito_version}") + testImplementation("org.xmlunit:xmlunit-legacy:${xmlunit_legacy_version}") + + implementation("org.glassfish.jaxb:jaxb-runtime:${xml_bind_jaxb_version}") +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/AgencySchemeReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/AgencySchemeReader.java new file mode 100644 index 0000000..7d22b6b --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/AgencySchemeReader.java @@ -0,0 +1,65 @@ +package com.epam.jsdmx.json20.structure.reader; + + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getBooleanJsonField; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Agency; +import com.epam.jsdmx.infomodel.sdmx30.AgencyImpl; +import com.epam.jsdmx.infomodel.sdmx30.AgencySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.apache.commons.collections.CollectionUtils; + +public class AgencySchemeReader extends MaintainableReader { + + private final OrganisationReader organisationReader; + + public AgencySchemeReader(VersionableReader versionableArtefact, + OrganisationReader organisationReader) { + super(versionableArtefact); + this.organisationReader = organisationReader; + } + + @Override + protected AgencySchemeImpl createMaintainableArtefact() { + return new AgencySchemeImpl(); + } + + @Override + public void readArtefact(JsonParser parser, AgencySchemeImpl agencyScheme) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.IS_PARTIAL: + agencyScheme.setPartial(getBooleanJsonField(parser)); + break; + case StructureUtils.AGENCIES: + List agencies = ReaderUtils.getArray(parser, (this::getAgency)); + if (CollectionUtils.isNotEmpty(agencies)) { + agencyScheme.setItems(agencies); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "AgencyScheme: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.AGENCY_SCHEMES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getAgencySchemes().addAll(artefacts); + } + + private Agency getAgency(JsonParser parser) { + return organisationReader.getOrganisation(parser, new AgencyImpl(), null); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/AnnotableReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/AnnotableReader.java new file mode 100644 index 0000000..15abc91 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/AnnotableReader.java @@ -0,0 +1,153 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.isNullValue; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.epam.jsdmx.infomodel.sdmx30.AnnotableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.AnnotableArtefactImpl; +import com.epam.jsdmx.infomodel.sdmx30.Annotation; +import com.epam.jsdmx.infomodel.sdmx30.AnnotationImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.InternationalUri; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import lombok.NoArgsConstructor; +import org.apache.commons.collections.CollectionUtils; + +@NoArgsConstructor +public class AnnotableReader { + + public AnnotationImpl readAnnotation(JsonParser parser) throws IOException { + AnnotationImpl annotation = new AnnotationImpl(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.ID: + setAnnotationId(parser, annotation); + break; + case StructureUtils.TITLE: + setAnnotationTitle(parser, annotation); + break; + case StructureUtils.VALUE: + setAnnotationValue(parser, annotation); + break; + case StructureUtils.TYPE: + setAnnotationType(parser, annotation); + break; + case StructureUtils.TEXT: + parser.nextToken(); + break; + case StructureUtils.TEXTS: + setAnnotationTexts(parser, annotation); + break; + case StructureUtils.LINKS: + setAnnotationLinks(parser, annotation); + break; + default: + throw new IllegalArgumentException("No such argument in Annotations: " + fieldName); + } + } + return annotation; + } + + private void setAnnotationTitle(JsonParser parser, AnnotationImpl annotation) throws IOException { + String title = ReaderUtils.getStringJsonField(parser); + if (title != null) { + annotation.setTitle(title); + } + } + + private void setAnnotationValue(JsonParser parser, AnnotationImpl annotation) throws IOException { + String value = ReaderUtils.getStringJsonField(parser); + if (value != null) { + annotation.setValue(value); + } + } + + private void setAnnotationType(JsonParser parser, AnnotationImpl annotation) throws IOException { + String type = ReaderUtils.getStringJsonField(parser); + if (type != null) { + annotation.setType(type); + } + } + + private void setAnnotationLinks(JsonParser parser, AnnotationImpl annotation) throws IOException { + List uriList = ReaderUtils.getArray(parser, parser1 -> getURIFromLink(parser)); + if (CollectionUtils.isNotEmpty(uriList)) { + annotation.setUrl(new InternationalUri(uriList.get(0))); + } + } + + private void setAnnotationTexts(JsonParser parser, AnnotationImpl annotation) throws IOException { + Map localizedText = new HashMap<>(); + parser.nextToken(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + localizedText.put(parser.getCurrentName(), parser.getText()); + } + annotation.setText(new InternationalString(localizedText)); + } + + private void setAnnotationId(JsonParser parser, AnnotationImpl annotation) throws IOException { + String id = ReaderUtils.getStringJsonField(parser); + if (id != null) { + annotation.setId(id); + } + } + + private URI getURIFromLink(JsonParser parser) { + try { + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.HREF: + case StructureUtils.URN: + case StructureUtils.REL: + case StructureUtils.TITLE: + case StructureUtils.TITLES: + case StructureUtils.TYPE: + case StructureUtils.HREFLANG: + parser.nextToken(); + break; + case StructureUtils.URI: + String uriString = ReaderUtils.getStringJsonField(parser); + if (uriString != null) { + return new URI(uriString); + } + break; + default: + throw new IllegalArgumentException("No such argument in Links: " + fieldName); + } + } + return null; + } catch (IOException | URISyntaxException e) { + throw new JsonRuntimeException(e); + } + } + + public AnnotableArtefact read(AnnotableArtefactImpl annotableArtefact, JsonParser parser) throws IOException { + parser.nextToken(); + if (isNullValue(parser)) { + return annotableArtefact; + } + List annotationList = new ArrayList<>(); + while (!JsonToken.END_ARRAY.equals(parser.currentToken())) { + if (JsonToken.START_OBJECT.equals(parser.nextToken())) { + AnnotationImpl annot = readAnnotation(parser); + annotationList.add(annot); + } + } + annotableArtefact.setAnnotations(annotationList); + return annotableArtefact; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/AttributeListReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/AttributeListReader.java new file mode 100644 index 0000000..77aa5c7 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/AttributeListReader.java @@ -0,0 +1,200 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getStringJsonField; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.isNullValue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.AttributeRelationship; +import com.epam.jsdmx.infomodel.sdmx30.DataAttribute; +import com.epam.jsdmx.infomodel.sdmx30.DataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.GroupRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureRelationship; +import com.epam.jsdmx.infomodel.sdmx30.MeasureRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeRef; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeRefImpl; +import com.epam.jsdmx.infomodel.sdmx30.ObservationRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + + +public class AttributeListReader { + + private final IdentifiableReader identifiableReader = new IdentifiableReader( + new AnnotableReader()); + + public AttributeDescriptorImpl getAttributeDescriptor(JsonParser parser) throws IOException { + parser.nextToken(); + if (isNullValue(parser)) { + return null; + } + AttributeDescriptorImpl attributeDescriptor = new AttributeDescriptorImpl(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.METADATA_ATTRIBUTE_USAGES: + List metadataAttributeRefs = ReaderUtils.getArray(parser, this::getMetadataAttributeRef); + if (CollectionUtils.isNotEmpty(metadataAttributeRefs)) { + List attributeRefs = metadataAttributeRefs.stream() + .map(MetadataAttributeRef.class::cast) + .collect(Collectors.toList()); + attributeDescriptor.setMetadataAttributes(attributeRefs); + } + break; + case StructureUtils.ATTRIBUTES: + List components = getComponents(parser); + if (CollectionUtils.isNotEmpty(components)) { + attributeDescriptor.setComponents(components); + } + break; + default: + identifiableReader.read(attributeDescriptor, parser); + break; + } + } + attributeDescriptor.setId(StructureUtils.ATTRIBUTE_DESCRIPTOR_ID); + return attributeDescriptor; + } + + private List getComponents(JsonParser parser) throws IOException { + List dataAttributes = new ArrayList<>(); + while (!JsonToken.END_ARRAY.equals(parser.nextToken())) { + if (JsonToken.START_OBJECT.equals(parser.currentToken())) { + DataAttributeImpl dataAttribute = new DataAttributeImpl(); + getComponent(parser, dataAttribute); + dataAttributes.add(dataAttribute); + } + } + return dataAttributes; + } + + private void getComponent(JsonParser parser, DataAttributeImpl dataAttribute) throws IOException { + dataAttribute.setMaxOccurs(1); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.CONCEPT_IDENTITY: + String conceptIdentity = getStringJsonField(parser); + if (conceptIdentity != null) { + dataAttribute.setConceptIdentity(new IdentifiableArtefactReferenceImpl(conceptIdentity)); + } + break; + case StructureUtils.IS_MANDATORY: + boolean isMandatory = ReaderUtils.getBooleanJsonField(parser); + if (isMandatory) { + dataAttribute.setMinOccurs(1); + } else { + dataAttribute.setMinOccurs(0); + } + break; + case StructureUtils.CONCEPT_ROLES: + List conceptRoles = ConceptRoleUtils.getConceptRoles(parser); + if (CollectionUtils.isNotEmpty(conceptRoles)) { + dataAttribute.setConceptRoles(conceptRoles); + } + break; + case StructureUtils.ATTRIBUTE_RELATIONSHIP: + dataAttribute.setAttributeRelationship(getAttributeRelationShip(parser)); + parser.nextToken(); + break; + case StructureUtils.MEASURE_RELATIONSHIP: + dataAttribute.setMeasureRelationship(getMeasureRelationship(parser)); + break; + case StructureUtils.LOCAL_REPRESENTATION: + dataAttribute.setLocalRepresentation(getRepresentation(parser)); + break; + default: + identifiableReader.read(dataAttribute, parser); + break; + } + } + } + + private MeasureRelationship getMeasureRelationship(JsonParser parser) throws IOException { + MeasureRelationshipImpl measureRelationship = new MeasureRelationshipImpl(); + measureRelationship.setMeasures(ReaderUtils.getListStrings(parser)); + return measureRelationship; + } + + private Representation getRepresentation(JsonParser parser) throws IOException { + RepresentationReader representationReader = new RepresentationReader(); + return representationReader.getRepresentations(parser); + } + + private MetadataAttributeRefImpl getMetadataAttributeRef(JsonParser parser) { + if (JsonToken.VALUE_NULL.equals(parser.currentToken())) { + return null; + } + try { + MetadataAttributeRefImpl metadataAttributeRef = new MetadataAttributeRefImpl(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.METADATA_ATTRIBUTE_REFERENCE: + String attributeId = getStringJsonField(parser); + if (attributeId != null) { + metadataAttributeRef.setId(attributeId); + } + break; + case StructureUtils.ATTRIBUTE_RELATIONSHIP: + metadataAttributeRef.setMetadataRelationship(getAttributeRelationShip(parser)); + parser.nextToken(); + break; + default: + identifiableReader.read(metadataAttributeRef, parser); + } + } + return metadataAttributeRef; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private AttributeRelationship getAttributeRelationShip(JsonParser parser) throws IOException { + parser.nextToken(); + if (isNullValue(parser)) { + return null; + } + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.currentName(); + switch (fieldName) { + case StructureUtils.DIMENSIONS: + DimensionRelationshipImpl dimensionRelationship = new DimensionRelationshipImpl(); + dimensionRelationship.setDimensions(ReaderUtils.getListStrings(parser)); + return dimensionRelationship; + case StructureUtils.OBSERVATION: + parser.nextToken(); + parser.nextToken(); + return new ObservationRelationshipImpl(); + case StructureUtils.GROUP: + GroupRelationshipImpl groupRelationship = new GroupRelationshipImpl(); + groupRelationship.setGroupKey(getStringJsonField(parser)); + return groupRelationship; + case StructureUtils.NONE: + parser.nextToken(); + parser.nextToken(); + return null; + default: + throw new IllegalArgumentException("no such AttributeRelationship: " + fieldName); + } + } + return null; + } + +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CategorisationReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CategorisationReader.java new file mode 100644 index 0000000..c9eb301 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CategorisationReader.java @@ -0,0 +1,68 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.Optional; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CategorisationImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.apache.commons.lang3.StringUtils; + +public class CategorisationReader extends MaintainableReader { + + public CategorisationReader(VersionableReader versionableArtefact) { + super(versionableArtefact); + } + + @Override + protected CategorisationImpl createMaintainableArtefact() { + return new CategorisationImpl(); + } + + @Override + public void readArtefact(JsonParser parser, CategorisationImpl categorisation) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.TARGET: + getTarget(parser).ifPresent(categorisation::setCategorizedBy); + break; + case StructureUtils.SOURCE: + getSource(parser).ifPresent(categorisation::setCategorizedArtefact); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "Categorisation: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.CATEGORISATIONS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getCategorisations().addAll(artefacts); + } + + private Optional getTarget(JsonParser parser) throws IOException { + String target = ReaderUtils.getStringJsonField(parser); + if (StringUtils.isBlank(target)) { + return Optional.empty(); + } + return Optional.of(new IdentifiableArtefactReferenceImpl(target)); + } + + private Optional getSource(JsonParser parser) throws IOException { + String source = ReaderUtils.getStringJsonField(parser); + if (StringUtils.isBlank(source)) { + return Optional.empty(); + } + return Optional.of(new IdentifiableArtefactReferenceImpl(source)); + } + +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CategorySchemeMapReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CategorySchemeMapReader.java new file mode 100644 index 0000000..1896e75 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CategorySchemeMapReader.java @@ -0,0 +1,56 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.apache.commons.collections.CollectionUtils; + +public class CategorySchemeMapReader extends MaintainableReader implements ItemMapReader { + + public CategorySchemeMapReader(VersionableReader versionableArtefact) { + super(versionableArtefact); + } + + @Override + protected CategorySchemeMapImpl createMaintainableArtefact() { + return new CategorySchemeMapImpl(); + } + + @Override + public void readArtefact(JsonParser parser, CategorySchemeMapImpl categorySchemeMap) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.TARGET: + getTargetSource(parser).ifPresent(categorySchemeMap::setTarget); + break; + case StructureUtils.SOURCE: + getTargetSource(parser).ifPresent(categorySchemeMap::setSource); + break; + case StructureUtils.ITEM_MAPS: + List itemMaps = ReaderUtils.getArray(parser, (this::getItemMap)); + if (CollectionUtils.isNotEmpty(itemMaps)) { + categorySchemeMap.setItemMaps(itemMaps); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "CategorySchemeMap: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.CATEGORY_SCHEME_MAPS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getCategorySchemeMaps().addAll(artefacts); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CategorySchemeReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CategorySchemeReader.java new file mode 100644 index 0000000..c89efb3 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CategorySchemeReader.java @@ -0,0 +1,80 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getBooleanJsonField; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Category; +import com.epam.jsdmx.infomodel.sdmx30.CategoryImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class CategorySchemeReader extends MaintainableReader { + + private final NameableReader nameableArtefact; + + public CategorySchemeReader(VersionableReader versionableArtefact, NameableReader nameableArtefact) { + super(versionableArtefact); + this.nameableArtefact = nameableArtefact; + } + + @Override + protected CategorySchemeImpl createMaintainableArtefact() { + return new CategorySchemeImpl(); + } + + @Override + public void readArtefact(JsonParser parser, CategorySchemeImpl categoryScheme) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.IS_PARTIAL: + categoryScheme.setPartial(getBooleanJsonField(parser)); + break; + case StructureUtils.CATEGORIES: + List categories = ReaderUtils.getArray(parser, (this::getCategory)); + if (CollectionUtils.isNotEmpty(categories)) { + categoryScheme.setItems(categories); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "CategoryScheme: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.CATEGORY_SCHEMES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getCategorySchemes().addAll(artefacts); + } + + private Category getCategory(JsonParser parser) { + try { + CategoryImpl category = new CategoryImpl(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + if (StructureUtils.CATEGORIES.equals(fieldName)) { + parser.nextToken(); + category.setHierarchy(ReaderUtils.getArray(parser, (this::getCategory))); + } else { + nameableArtefact.read(category, parser); + } + } + return category; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodeImplReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodeImplReader.java new file mode 100644 index 0000000..e84fdbf --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodeImplReader.java @@ -0,0 +1,6 @@ +package com.epam.jsdmx.json20.structure.reader; + +import com.epam.jsdmx.infomodel.sdmx30.CodeImpl; + +public class CodeImplReader implements CodeReader { +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodeReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodeReader.java new file mode 100644 index 0000000..a0102ef --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodeReader.java @@ -0,0 +1,49 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; + +import java.io.IOException; +import java.util.Map; + +import com.epam.jsdmx.infomodel.sdmx30.CodeImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + +public interface CodeReader { + + default T getCode(JsonParser parser, + T code, + NameableReader nameableReader, + Map codeWithParentId) throws IOException { + String parentId = null; + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.PARENT: + parser.nextToken(); + parentId = parser.getText(); + code.setParentId(parentId); + break; + case StructureUtils.ID: + case StructureUtils.ANNOTATIONS: + case StructureUtils.NAMES: + case StructureUtils.DESCRIPTIONS: + case StructureUtils.DESCRIPTION: + case StructureUtils.NAME: + nameableReader.read(code, parser); + break; + default: + readExtendedCodeFields(parser, code); + break; + } + } + codeWithParentId.put(code, parentId); + return code; + } + + default void readExtendedCodeFields(JsonParser parser, T code) throws IOException { + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodelistExtensionReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodelistExtensionReader.java new file mode 100644 index 0000000..6550b34 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodelistExtensionReader.java @@ -0,0 +1,188 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.BaseCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.CascadeValue; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.ExclusiveCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.InclusiveCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.MemberValue; +import com.epam.jsdmx.infomodel.sdmx30.MemberValueImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class CodelistExtensionReader { + + public List getCodeListExtensions(JsonParser parser) throws IOException { + List codelistExtensions = new ArrayList<>(); + int sequence = 0; + while (!JsonToken.END_ARRAY.equals(parser.nextToken())) { + if (JsonToken.START_OBJECT.equals(parser.currentToken())) { + CodelistExtensionImpl codelistExtension = getCodelistExtension(parser, sequence); + if (codelistExtension != null) { + codelistExtensions.add(codelistExtension); + } + sequence++; + } + } + return codelistExtensions; + } + + private CodelistExtensionImpl getCodelistExtension(JsonParser parser, int sequence) throws IOException { + CodelistExtensionImpl codelistExtension = new CodelistExtensionImpl(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + if (!checkIsNotEmptyObjectAndSkipUntilFieldName(parser)) { + return null; + } + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.PREFIX: + parser.nextToken(); + String prefix = parser.getValueAsString(); + codelistExtension.setPrefix(prefix); + break; + case StructureUtils.SEQUENCE: + codelistExtension.setSequence(sequence); + break; + case StructureUtils.CODE_LIST: + parser.nextToken(); + String codelist = parser.getValueAsString(); + if (codelist != null) { + codelistExtension.setCodelist(new MaintainableArtefactReference(codelist)); + } + break; + case StructureUtils.EXCLUSIVE_CODE_SELECTION: + parser.nextToken(); + ExclusiveCodeSelectionImpl exclusiveCodeSelection = new ExclusiveCodeSelectionImpl(); + setCodeSelection(parser, exclusiveCodeSelection); + codelistExtension.setCodeSelection(exclusiveCodeSelection); + break; + case StructureUtils.INCLUSIVE_CODE_SELECTION: + parser.nextToken(); + InclusiveCodeSelectionImpl inclusiveCodeSelection = new InclusiveCodeSelectionImpl(); + setCodeSelection(parser, inclusiveCodeSelection); + codelistExtension.setCodeSelection(inclusiveCodeSelection); + break; + default: + parser.nextToken(); + break; + } + } + return codelistExtension; + } + + private void setCodeSelection(JsonParser parser, BaseCodeSelectionImpl selection) throws IOException { + boolean isWildcardedValues = false; + boolean isMemberValues = false; + while (!JsonToken.END_OBJECT.equals(parser.currentToken())) { + if (!checkIsNotEmptyObjectAndSkipUntilFieldName(parser)) { + return; + } + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.MEMBER_VALUES: + isMemberValues = true; + readMemberValues(parser, selection, isWildcardedValues); + break; + case StructureUtils.WILDCARDED_MEMBER_VALUES: + isWildcardedValues = true; + readWildcardedValues(parser, selection, isMemberValues); + break; + default: + throw new IllegalArgumentException("no such argument in Code selection: " + fieldName); + } + } + } + + private void readWildcardedValues(JsonParser parser, BaseCodeSelectionImpl selection, boolean isMemberValues) throws IOException { + parser.nextToken(); + if (isMemberValues) { + throw new IllegalArgumentException("Cannot specify both wildcarded and explicit selections"); + } + List wildcardedMembers = getWildcardedMembers(parser); + if (CollectionUtils.isNotEmpty(wildcardedMembers)) { + selection.setMembers(wildcardedMembers); + } + } + + private void readMemberValues(JsonParser parser, BaseCodeSelectionImpl selection, boolean isWildcardedValues) throws IOException { + parser.nextToken(); + if (isWildcardedValues) { + throw new IllegalArgumentException("Cannot specify both wildcarded and explicit selections"); + } + List memberValues = ReaderUtils.getArray(parser, this::getMemberValue); + if (CollectionUtils.isNotEmpty(memberValues)) { + selection.setMembers(memberValues); + } + parser.nextToken(); + } + + private List getWildcardedMembers(JsonParser parser) throws IOException { + List stringList = ReaderUtils.getListStrings(parser); + return stringList.stream() + .filter(Objects::nonNull) + .map(str -> { + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setValue(str); + return memberValue; + }) + .collect(Collectors.toList()); + } + + private MemberValue getMemberValue(JsonParser parser) { + try { + MemberValueImpl memberValue = new MemberValueImpl(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + if (!checkIsNotEmptyObjectAndSkipUntilFieldName(parser)) { + return null; + } + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.VALUE: + parser.nextToken(); + String value = parser.getText(); + memberValue.setValue(value); + break; + case StructureUtils.CASCADE_VALUES: + parser.nextToken(); + String cascadeSelection = parser.getText(); + CascadeValue cascadeValue; + switch (cascadeSelection) { + case StructureUtils.TRUE: + cascadeValue = CascadeValue.TRUE; + break; + case StructureUtils.FALSE: + cascadeValue = CascadeValue.FALSE; + break; + case StructureUtils.EXCLUDE_ROOT: + cascadeValue = CascadeValue.EXCLUDE_ROOT; + break; + default: + throw new IllegalArgumentException("Unexpected enum constant: " + cascadeSelection); + } + memberValue.setCascadeValue(cascadeValue); + break; + default: + // unrecognized field, skip it + parser.nextToken(); + break; + } + } + return memberValue; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodelistReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodelistReader.java new file mode 100644 index 0000000..59faa40 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CodelistReader.java @@ -0,0 +1,88 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.apache.commons.collections.CollectionUtils; + +public class CodelistReader extends MaintainableReader { + + private final NameableReader nameableReader; + private final CodelistExtensionReader codelistExtensionReader; + private final CodeImplReader codeImplReader; + Map codeWithParentId = new HashMap<>(); + + public CodelistReader(VersionableReader versionableArtefact, + NameableReader nameableArtefact, + CodelistExtensionReader codelistExtensionReader, + CodeImplReader codeImplReader) { + super(versionableArtefact); + this.nameableReader = nameableArtefact; + this.codelistExtensionReader = codelistExtensionReader; + this.codeImplReader = codeImplReader; + } + + @Override + protected CodelistImpl createMaintainableArtefact() { + return new CodelistImpl(); + } + + @Override + public void readArtefact(JsonParser parser, CodelistImpl codeList) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.CODES: + List codeImpls = ReaderUtils.getArray(parser, this::getCodeImpl); + if (CollectionUtils.isNotEmpty(codeImpls)) { + codeList.setItems(List.copyOf(codeImpls)); + } + break; + case StructureUtils.CODE_LIST_EXTENSIONS: + parser.nextToken(); + List codeListExtensions = codelistExtensionReader.getCodeListExtensions(parser); + if (CollectionUtils.isNotEmpty(codeListExtensions)) { + codeList.setExtensions(codeListExtensions); + } + break; + case StructureUtils.IS_PARTIAL: + boolean isPartial = ReaderUtils.getBooleanJsonField(parser); + codeList.setPartial(isPartial); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "CodeList: " + fieldName); + } + } + + private CodeImpl getCodeImpl(JsonParser parser) { + try { + return codeImplReader.getCode(parser, new CodeImpl(), nameableReader, codeWithParentId); + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + @Override + protected String getName() { + return StructureUtils.CODE_LISTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getCodelists().addAll(artefacts); + } + + @Override + protected void clean() { + codeWithParentId.clear(); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ConceptRoleUtils.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ConceptRoleUtils.java new file mode 100644 index 0000000..ba8b29c --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ConceptRoleUtils.java @@ -0,0 +1,33 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; + +import com.fasterxml.jackson.core.JsonParser; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ConceptRoleUtils { + + public static List getConceptRoles(JsonParser parser) throws IOException { + List identifiableArtefactReferences = new ArrayList<>(); + List conceptRolesStrings = ReaderUtils.getListStrings(parser); + if (conceptRolesStrings.isEmpty()) { + return Collections.emptyList(); + } + for (String conceptRole : conceptRolesStrings) { + if (conceptRole != null) { + IdentifiableArtefactReferenceImpl identifiableArtefactReference = + new IdentifiableArtefactReferenceImpl(conceptRole); + identifiableArtefactReferences.add(identifiableArtefactReference); + } + } + return identifiableArtefactReferences; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ConceptSchemeMapReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ConceptSchemeMapReader.java new file mode 100644 index 0000000..f44fb04 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ConceptSchemeMapReader.java @@ -0,0 +1,56 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.apache.commons.collections.CollectionUtils; + +public class ConceptSchemeMapReader extends MaintainableReader implements ItemMapReader { + + public ConceptSchemeMapReader(VersionableReader versionableArtefact) { + super(versionableArtefact); + } + + @Override + protected ConceptSchemeMapImpl createMaintainableArtefact() { + return new ConceptSchemeMapImpl(); + } + + @Override + public void readArtefact(JsonParser parser, ConceptSchemeMapImpl conceptSchemeMap) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.TARGET: + getTargetSource(parser).ifPresent(conceptSchemeMap::setTarget); + break; + case StructureUtils.SOURCE: + getTargetSource(parser).ifPresent(conceptSchemeMap::setSource); + break; + case StructureUtils.ITEM_MAPS: + List itemMaps = ReaderUtils.getArray(parser, (this::getItemMap)); + if (CollectionUtils.isNotEmpty(itemMaps)) { + conceptSchemeMap.setItemMaps(itemMaps); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "ConceptSchemeMap: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.CONCEPT_SCHEME_MAPS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getConceptSchemeMaps().addAll(artefacts); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ConceptSchemeReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ConceptSchemeReader.java new file mode 100644 index 0000000..693565b --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ConceptSchemeReader.java @@ -0,0 +1,127 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Concept; +import com.epam.jsdmx.infomodel.sdmx30.ConceptImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.IsoConceptReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class ConceptSchemeReader extends MaintainableReader { + private final NameableReader nameableReader; + + public ConceptSchemeReader(VersionableReader versionableArtefact, NameableReader nameableReader) { + super(versionableArtefact); + this.nameableReader = nameableReader; + } + + @Override + protected ConceptSchemeImpl createMaintainableArtefact() { + return new ConceptSchemeImpl(); + } + + @Override + public void readArtefact(JsonParser parser, ConceptSchemeImpl conceptScheme) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.IS_PARTIAL: + conceptScheme.setPartial(ReaderUtils.getBooleanJsonField(parser)); + break; + case StructureUtils.CONCEPTS: + List concepts = ReaderUtils.getArray(parser, this::getConcept); + if (CollectionUtils.isNotEmpty(concepts)) { + conceptScheme.setItems(concepts); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "ConceptScheme: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.CONCEPT_SCHEMES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getConceptSchemes().addAll(artefacts); + } + + private Concept getConcept(JsonParser parser) { + try { + ConceptImpl concept = new ConceptImpl(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.ISOCONCEPTREFERENCE: + concept.setIsoConceptReference(getIsoConceptReference(parser)); + break; + case StructureUtils.CORE_REPRESENTATION: + RepresentationReader reader = new RepresentationReader(); + Representation representations = reader.getRepresentations(parser); + if (representations != null) { + concept.setCoreRepresentation(representations); + } + break; + default: + nameableReader.read(concept, parser); + break; + } + } + return concept; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private IsoConceptReferenceImpl getIsoConceptReference(JsonParser parser) throws IOException { + parser.nextToken(); + IsoConceptReferenceImpl isoConceptReference = new IsoConceptReferenceImpl(); + if (parser.currentToken() + .equals(JsonToken.START_OBJECT) && parser.nextToken() + .equals(JsonToken.END_OBJECT)) { + return null; + } + while (!JsonToken.END_OBJECT.equals(parser.currentToken())) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.CONCEPT_SCHEME_ID: + String conceptSchemeId = ReaderUtils.getStringJsonField(parser); + if (conceptSchemeId != null) { + isoConceptReference.setSchemeId(conceptSchemeId); + } + parser.nextToken(); + break; + case StructureUtils.CONCEPT_ID: + String conceptId = ReaderUtils.getStringJsonField(parser); + if (conceptId != null) { + isoConceptReference.setConceptId(conceptId); + } + parser.nextToken(); + break; + case StructureUtils.CONCEPT_AGENCY: + String conceptAgency = ReaderUtils.getStringJsonField(parser); + if (conceptAgency != null) { + isoConceptReference.setAgency(conceptAgency); + } + parser.nextToken(); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "IsoConceptReference: " + fieldName); + } + } + return isoConceptReference; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ContactReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ContactReader.java new file mode 100644 index 0000000..5ee7e32 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ContactReader.java @@ -0,0 +1,109 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getLocalizedField; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; +import java.util.Map; + +import com.epam.jsdmx.infomodel.sdmx30.Contact; +import com.epam.jsdmx.infomodel.sdmx30.ContactImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class ContactReader { + + public Contact getContact(JsonParser parser) { + try { + ContactImpl contact = new ContactImpl(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.NAME: + String name = ReaderUtils.getFieldAsString(parser); + contact.setName(name); + break; + case StructureUtils.DEPARTMENT: + String department = ReaderUtils.getFieldAsString(parser); + contact.setOrganizationUnit(department); + break; + case StructureUtils.ROLE: + Map roles = getLocalizedField(parser); + setRoles(contact, roles); + break; + case StructureUtils.TELEPHONES: + List telephones = ReaderUtils.getListStrings(parser); + setTelephones(contact, telephones); + break; + case StructureUtils.FAXES: + List faxes = ReaderUtils.getListStrings(parser); + setFaxes(contact, faxes); + break; + case StructureUtils.X_400_S: + List x400 = ReaderUtils.getListStrings(parser); + setX400(contact, x400); + break; + case StructureUtils.EMAILS: + List emails = ReaderUtils.getListStrings(parser); + setEmail(contact, emails); + break; + case StructureUtils.URIS: + List uris = ReaderUtils.getListStrings(parser); + setURI(contact, uris); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "Contacts: " + fieldName); + } + } + return contact; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + private void setRoles(ContactImpl contact, Map roles) { + if (roles != null) { + contact.setResponsibility(new InternationalString(roles)); + } + } + + private void setTelephones(ContactImpl contact, List telephones) { + if (CollectionUtils.isNotEmpty(telephones)) { + contact.setTelephone(telephones.get(0)); + } + } + + private void setFaxes(ContactImpl contact, List faxes) { + if (CollectionUtils.isNotEmpty(faxes)) { + contact.setFax(faxes.get(0)); + } + } + + private void setX400(ContactImpl contact, List x400) { + if (CollectionUtils.isNotEmpty(x400)) { + contact.setX400(x400.get(0)); + } + } + + private void setEmail(ContactImpl contact, List emails) { + if (CollectionUtils.isNotEmpty(emails)) { + contact.setEmail(emails.get(0)); + } + } + + private void setURI(ContactImpl contact, List uris) throws URISyntaxException { + if (CollectionUtils.isNotEmpty(uris) && uris.get(0) != null) { + contact.setUri(new URI(uris.get(0))); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CubeRegionReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CubeRegionReader.java new file mode 100644 index 0000000..b7ab016 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/CubeRegionReader.java @@ -0,0 +1,133 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.CubeRegion; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionImpl; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionKey; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionKeyImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.SelectionValue; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class CubeRegionReader { + + private final MemberSelectionReader memberSelectionReader; + private final AnnotableReader annotableReader; + + public CubeRegionReader(MemberSelectionReader memberSelectionReader, AnnotableReader annotableReader) { + this.memberSelectionReader = memberSelectionReader; + this.annotableReader = annotableReader; + } + + public CubeRegion getCubeRegion(JsonParser parser) { + try { + CubeRegionImpl cubeRegion = new CubeRegionImpl(); + if (parser.currentToken() + .equals(JsonToken.START_OBJECT) && parser.nextToken() + .equals(JsonToken.END_OBJECT)) { + return null; + } + while (!JsonToken.END_OBJECT.equals(parser.currentToken())) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.INCLUDE: + boolean include = ReaderUtils.getBooleanJsonField(parser); + cubeRegion.setIncluded(include); + parser.nextToken(); + break; + case StructureUtils.COMPONENTS: + List memberSelections = ReaderUtils.getArray(parser, (this::getMemberSelection)); + if (CollectionUtils.isNotEmpty(memberSelections)) { + cubeRegion.setMemberSelections(memberSelections); + } + parser.nextToken(); + break; + case StructureUtils.KEY_VALUES: + List cubeRegionKeys = ReaderUtils.getArray(parser, (this::getKeyValue)); + if (CollectionUtils.isNotEmpty(cubeRegionKeys)) { + cubeRegion.setCubeRegionKeys(cubeRegionKeys); + } + parser.nextToken(); + break; + default: + annotableReader.read(cubeRegion, parser); + parser.nextToken(); + break; + } + } + return cubeRegion; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private MemberSelection getMemberSelection(JsonParser parser) { + return memberSelectionReader.getMemberSelection(parser); + } + + public CubeRegionKey getKeyValue(JsonParser parser) { + try { + CubeRegionKeyImpl cubeRegionKey = new CubeRegionKeyImpl(); + if (parser.currentToken() + .equals(JsonToken.START_OBJECT) && parser.nextToken() + .equals(JsonToken.END_OBJECT)) { + return null; + } + List selectionValues = new ArrayList<>(); + while (!JsonToken.END_OBJECT.equals(parser.currentToken())) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.ID: + cubeRegionKey.setComponentId(ReaderUtils.getFieldAsString(parser)); + parser.nextToken(); + break; + case StructureUtils.VALID_FROM: + cubeRegionKey.setValidFrom(ReaderUtils.getInstantObj(parser)); + parser.nextToken(); + break; + case StructureUtils.VALID_TO: + cubeRegionKey.setValidTo(ReaderUtils.getInstantObj(parser)); + parser.nextToken(); + break; + case StructureUtils.INCLUDE: + boolean include = ReaderUtils.getBooleanJsonField(parser); + cubeRegionKey.setIncluded(include); + parser.nextToken(); + break; + case StructureUtils.REMOVE_PREFIX: + boolean removePrefix = ReaderUtils.getBooleanJsonField(parser); + cubeRegionKey.setRemovePrefix(removePrefix); + parser.nextToken(); + break; + case StructureUtils.TIME_RANGE: + List timeRanges = memberSelectionReader.getTimeRanges(parser); + if (CollectionUtils.isNotEmpty(timeRanges)) { + selectionValues.addAll(timeRanges); + } + parser.nextToken(); + break; + case StructureUtils.VALUES: + List values = ReaderUtils.getArray(parser, (memberSelectionReader::getMemberValue)); + selectionValues.addAll(values); + parser.nextToken(); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + " CubeRegionKey: " + fieldName); + } + } + cubeRegionKey.setSelectionValues(selectionValues); + return cubeRegionKey; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataConstraintReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataConstraintReader.java new file mode 100644 index 0000000..082c611 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataConstraintReader.java @@ -0,0 +1,124 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getStringJsonField; +import static com.epam.jsdmx.json20.structure.writer.StructureUtils.STRING_CONSTRAINT_ROLE; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegion; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySet; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class DataConstraintReader extends MaintainableReader { + + private final ReleaseCalendarReader releaseCalendarReader; + private final DataKeySetReader dataKeySetReader; + private final CubeRegionReader cubeRegionReader; + + public DataConstraintReader(VersionableReader versionableArtefact, + ReleaseCalendarReader releaseCalendarReader, + DataKeySetReader dataKeySetReader, + CubeRegionReader cubeRegionReader) { + super(versionableArtefact); + this.releaseCalendarReader = releaseCalendarReader; + this.dataKeySetReader = dataKeySetReader; + this.cubeRegionReader = cubeRegionReader; + } + + @Override + protected DataConstraintImpl createMaintainableArtefact() { + return new DataConstraintImpl(); + } + + @Override + public void readArtefact(JsonParser parser, DataConstraintImpl dataConstraint) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.ROLE: + dataConstraint.setConstraintRoleType(STRING_CONSTRAINT_ROLE.get(ReaderUtils.getFieldAsString(parser))); + break; + case StructureUtils.RELEASE_CALENDAR: + dataConstraint.setReleaseCalendar(releaseCalendarReader.getReleaseCalendar(parser)); + break; + case StructureUtils.CONSTRAINT_ATTACHMENT: + dataConstraint.setConstrainedArtefacts(getConstraintAttachment(parser)); + break; + case StructureUtils.DATA_KEY_SETS: + List dataKeySets = ReaderUtils.getArray(parser, (dataKeySetReader::getDataKeySet)); + if (CollectionUtils.isNotEmpty(dataKeySets)) { + dataConstraint.setDataContentKeys(dataKeySets); + } + break; + case StructureUtils.CUBE_REGIONS: + List cubeRegions = ReaderUtils.getArray(parser, (cubeRegionReader::getCubeRegion)); + if (CollectionUtils.isNotEmpty(cubeRegions)) { + dataConstraint.setCubeRegions(cubeRegions); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "DataConstraint: " + fieldName); + } + } + + private List getConstraintAttachment(JsonParser parser) throws IOException { + parser.nextToken(); + List artefactReferences = new ArrayList<>(); + if (parser.currentToken() + .equals(JsonToken.START_OBJECT) && parser.nextToken() + .equals(JsonToken.END_OBJECT)) { + return Collections.emptyList(); + } + while (parser.currentToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.DATA_PROVIDER: + String metadataProvider = getStringJsonField(parser); + if (metadataProvider != null) { + artefactReferences.add(new IdentifiableArtefactReferenceImpl(metadataProvider)); + } + parser.nextToken(); + break; + case StructureUtils.DATA_STRUCTURES: + case StructureUtils.DATAFLOWS: + case StructureUtils.PROVISION_AGREEMENTS: + List metadataSets = ReaderUtils.getListStrings(parser); + List references = metadataSets.stream() + .filter(Objects::nonNull) + .map(IdentifiableArtefactReferenceImpl::new) + .collect(Collectors.toList()); + artefactReferences.addAll(references); + parser.nextToken(); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + " ConstraintAttachment: " + fieldName); + } + } + return artefactReferences; + } + + @Override + protected String getName() { + return StructureUtils.DATA_CONSTRAINTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getDataConstraints().addAll(artefacts); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataConsumerSchemeReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataConsumerSchemeReader.java new file mode 100644 index 0000000..6210b92 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataConsumerSchemeReader.java @@ -0,0 +1,77 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumer; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerSchemeImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.apache.commons.collections.CollectionUtils; + +public class DataConsumerSchemeReader extends MaintainableReader { + + private final OrganisationReader organisationReader; + private final Map dataConsumerWithParent = new HashMap<>(); + + public DataConsumerSchemeReader(VersionableReader versionableArtefact, + OrganisationReader organisationReader) { + super(versionableArtefact); + this.organisationReader = organisationReader; + } + + @Override + protected DataConsumerSchemeImpl createMaintainableArtefact() { + return new DataConsumerSchemeImpl(); + } + + @Override + public void readArtefact(JsonParser parser, DataConsumerSchemeImpl dataConsumerScheme) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.IS_PARTIAL: + dataConsumerScheme.setPartial(ReaderUtils.getBooleanJsonField(parser)); + break; + case StructureUtils.DATA_CONSUMERS: + List dataConsumers = ReaderUtils.getArray(parser, (this::getDataConsumer)); + if (CollectionUtils.isNotEmpty(dataConsumers)) { + Map> dataConsumerListMap = organisationReader.formHierarchy(dataConsumerWithParent); + for (Map.Entry> consumersHier : dataConsumerListMap.entrySet()) { + List value = consumersHier.getValue(); + List hierarchy = new ArrayList<>(value); + consumersHier.getKey().setHierarchy(hierarchy); + } + dataConsumerScheme.setItems(dataConsumers); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "DataConsumerScheme: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.DATA_CONSUMER_SCHEMES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getDataConsumerSchemes().addAll(artefacts); + } + + private DataConsumer getDataConsumer(JsonParser parser) { + return organisationReader.getOrganisation(parser, new DataConsumerImpl(), dataConsumerWithParent); + } + + @Override + protected void clean() { + dataConsumerWithParent.clear(); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataFlowReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataFlowReader.java new file mode 100644 index 0000000..1b35da1 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataFlowReader.java @@ -0,0 +1,44 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; + +public class DataFlowReader extends MaintainableReader { + + public DataFlowReader(VersionableReader versionableArtefact) { + super(versionableArtefact); + } + + @Override + protected DataflowImpl createMaintainableArtefact() { + return new DataflowImpl(); + } + + @Override + public void readArtefact(JsonParser parser, DataflowImpl dataflow) throws IOException { + String fieldName = parser.getCurrentName(); + if (StructureUtils.STRUCTURE.equals(fieldName)) { + String urn = ReaderUtils.getStringJsonField(parser); + if (urn != null) { + dataflow.setStructure(new MaintainableArtefactReference(urn)); + } + } + } + + @Override + protected String getName() { + return StructureUtils.DATAFLOWS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getDataflows().addAll(artefacts); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataKeySetReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataKeySetReader.java new file mode 100644 index 0000000..cd175b3 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataKeySetReader.java @@ -0,0 +1,164 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.ComponentValue; +import com.epam.jsdmx.infomodel.sdmx30.ComponentValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataKey; +import com.epam.jsdmx.infomodel.sdmx30.DataKeyImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySet; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySetImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class DataKeySetReader { + + private final AnnotableReader annotableReader; + private final MemberSelectionReader memberSelectionReader; + + public DataKeySetReader(AnnotableReader annotableReader, + MemberSelectionReader memberSelectionReader) { + this.annotableReader = annotableReader; + this.memberSelectionReader = memberSelectionReader; + } + + public DataKeySet getDataKeySet(JsonParser parser) { + try { + parser.nextToken(); + DataKeySetImpl dataKeySet = new DataKeySetImpl(); + if (parser.currentToken() + .equals(JsonToken.START_OBJECT) && parser.nextToken() + .equals(JsonToken.END_OBJECT)) { + return null; + } + while (!JsonToken.END_OBJECT.equals(parser.currentToken())) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.IS_INCLUDED: + dataKeySet.setIncluded(ReaderUtils.getBooleanJsonField(parser)); + parser.nextToken(); + break; + case StructureUtils.KEYS: + List dataKeys = ReaderUtils.getArray(parser, this::getKey); + if (CollectionUtils.isNotEmpty(dataKeys)) { + dataKeySet.setKeys(dataKeys); + } + parser.nextToken(); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + " DataKeySet: " + fieldName); + } + } + return dataKeySet; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private DataKey getKey(JsonParser parser) { + try { + parser.nextToken(); + DataKeyImpl dataKey = new DataKeyImpl(); + if (parser.currentToken() + .equals(JsonToken.START_OBJECT) && parser.nextToken() + .equals(JsonToken.END_OBJECT)) { + return null; + } + + while (!JsonToken.END_OBJECT.equals(parser.currentToken())) { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.VALID_FROM: + dataKey.setValidFrom(ReaderUtils.getInstantObj(parser)); + parser.nextToken(); + break; + case StructureUtils.VALID_TO: + dataKey.setValidTo(ReaderUtils.getInstantObj(parser)); + parser.nextToken(); + break; + case StructureUtils.INCLUDE: + boolean include = ReaderUtils.getBooleanJsonField(parser); + dataKey.setIncluded(include); + parser.nextToken(); + break; + case StructureUtils.COMPONENTS: + List memberSelections = ReaderUtils.getArray(parser, (this::getMemberSelection)); + if (CollectionUtils.isNotEmpty(memberSelections)) { + dataKey.setMemberSelections(memberSelections); + } + parser.nextToken(); + break; + case StructureUtils.KEY_VALUES: + List keyValues = ReaderUtils.getArray(parser, (this::getKeyValue)); + if (CollectionUtils.isNotEmpty(keyValues)) { + dataKey.setKeyValues(keyValues); + } + parser.nextToken(); + break; + default: + annotableReader.read(dataKey, parser); + parser.nextToken(); + break; + } + } + return dataKey; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private ComponentValue getKeyValue(JsonParser parser) { + try { + parser.nextToken(); + ComponentValueImpl componentValue = new ComponentValueImpl(); + + if (parser.currentToken() + .equals(JsonToken.START_OBJECT) && parser.nextToken() + .equals(JsonToken.END_OBJECT)) { + return null; + } + + while (!JsonToken.END_OBJECT.equals(parser.currentToken())) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.ID: + String id = ReaderUtils.getStringJsonField(parser); + componentValue.setComponentId(id); + parser.nextToken(); + break; + case StructureUtils.INCLUDE: + boolean include = ReaderUtils.getBooleanJsonField(parser); + componentValue.setIncluded(include); + parser.nextToken(); + break; + case StructureUtils.REMOVE_PREFIX: + boolean removePrefix = ReaderUtils.getBooleanJsonField(parser); + componentValue.setRemovePrefix(removePrefix); + parser.nextToken(); + break; + case StructureUtils.VALUE: + String value = ReaderUtils.getStringJsonField(parser); + componentValue.setValue(value); + parser.nextToken(); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + " ComponentValue: " + fieldName); + } + } + return componentValue; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private MemberSelection getMemberSelection(JsonParser parser) { + return memberSelectionReader.getMemberSelection(parser); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataProviderSchemeReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataProviderSchemeReader.java new file mode 100644 index 0000000..eb5f08b --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataProviderSchemeReader.java @@ -0,0 +1,77 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataProvider; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderSchemeImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.apache.commons.collections.CollectionUtils; + +public class DataProviderSchemeReader extends MaintainableReader { + + private final OrganisationReader organisationReader; + private final Map dataProviderSchemeMap = new HashMap<>(); + + public DataProviderSchemeReader(VersionableReader versionableArtefact, + OrganisationReader organisationReader) { + super(versionableArtefact); + this.organisationReader = organisationReader; + } + + @Override + protected DataProviderSchemeImpl createMaintainableArtefact() { + return new DataProviderSchemeImpl(); + } + + @Override + public void readArtefact(JsonParser parser, DataProviderSchemeImpl dataProviderScheme) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.IS_PARTIAL: + dataProviderScheme.setPartial(ReaderUtils.getBooleanJsonField(parser)); + break; + case StructureUtils.DATA_PROVIDERS: + List dataProviders = ReaderUtils.getArray(parser, (this::getDataProvider)); + if (CollectionUtils.isNotEmpty(dataProviders)) { + Map> dataProviderListMap = organisationReader.formHierarchy(dataProviderSchemeMap); + for (Map.Entry> consumersHier : dataProviderListMap.entrySet()) { + List value = consumersHier.getValue(); + List hierarchy = new ArrayList<>(value); + consumersHier.getKey().setHierarchy(hierarchy); + } + dataProviderScheme.setItems(dataProviders); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "DataProviderScheme: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.DATA_PROVIDER_SCHEMES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getDataProviderSchemes().addAll(artefacts); + } + + private DataProvider getDataProvider(JsonParser parser) { + return organisationReader.getOrganisation(parser, new DataProviderImpl(), dataProviderSchemeMap); + } + + @Override + protected void clean() { + dataProviderSchemeMap.clear(); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataReader.java new file mode 100644 index 0000000..6f95b6f --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataReader.java @@ -0,0 +1,93 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + +public class DataReader { + + private final List> readers; + + public DataReader(List> readers) { + this.readers = readers; + } + + public ArtefactsImpl read(JsonParser parser) throws IOException { + + ArtefactsImpl artefacts = new ArtefactsImpl(); + if (JsonToken.START_OBJECT.equals(parser.currentToken()) && JsonToken.END_OBJECT.equals(parser.nextToken())) { + return null; + } + while (!JsonToken.END_OBJECT.equals(parser.currentToken())) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String currentParserName = parser.getCurrentName(); + switch (currentParserName) { + case StructureUtils.STRUCTURE_MAP: + case StructureUtils.CATEGORISATIONS: + case StructureUtils.CATEGORY_SCHEMES: + case StructureUtils.CODE_LISTS: + case StructureUtils.CONCEPT_SCHEMES: + case StructureUtils.DATA_STRUCTURES: + case StructureUtils.METADATA_STRUCTURES: + case StructureUtils.HIERARCHIES: + case StructureUtils.REPRESENTATION_MAPS: + case StructureUtils.DATAFLOWS: + case StructureUtils.METADATAFLOWS: + case StructureUtils.AGENCY_SCHEMES: + case StructureUtils.CATEGORY_SCHEME_MAPS: + case StructureUtils.CONCEPT_SCHEME_MAPS: + case StructureUtils.DATA_CONSUMER_SCHEMES: + case StructureUtils.DATA_PROVIDER_SCHEMES: + case StructureUtils.HIERARCHY_ASSOCIATIONS: + case StructureUtils.METADATA_CONSTRAINTS: + case StructureUtils.METADATA_PROVIDER_SCHEMES: + case StructureUtils.METADATA_PROVISION_AGREEMENTS: + case StructureUtils.ORGANISATION_UNIT_SCHEMES: + case StructureUtils.ORGANISATION_SCHEME_MAPS: + case StructureUtils.PROCESSES: + case StructureUtils.PROVISION_AGREEMENTS: + case StructureUtils.REPORTING_TAXONOMY_MAPS: + case StructureUtils.REPORTING_TAXONOMIES: + case StructureUtils.VALUE_LISTS: + case StructureUtils.GEOGRAPHIC_CODELISTS: + case StructureUtils.GEO_GRID_CODELISTS: + case StructureUtils.DATA_CONSTRAINTS: + Optional> jsonReader = readers.stream() + .filter(read -> currentParserName.equals(read.getName())) + .findAny(); + if (jsonReader.isPresent()) { + addArtefacts(parser, jsonReader.get(), artefacts); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "Artefacts: " + currentParserName); + } + parser.nextToken(); + } + return artefacts; + } + + private void addArtefacts(JsonParser parser, + MaintainableReader maintainableReader, + ArtefactsImpl artefacts) throws IOException { + List artefactList = ReaderUtils.getArray(parser, artefactParser -> { + try { + T art = maintainableReader.read(artefactParser); + maintainableReader.clean(); + return art; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + }); + maintainableReader.setArtefacts(artefacts, Set.copyOf(artefactList)); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataStructureDefinitionReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataStructureDefinitionReader.java new file mode 100644 index 0000000..0d035d5 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DataStructureDefinitionReader.java @@ -0,0 +1,89 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + +public class DataStructureDefinitionReader extends MaintainableReader { + + private final IdentifiableReader identifiableReader; + + public DataStructureDefinitionReader(VersionableReader versionableArtefact, IdentifiableReader identifiableReader) { + super(versionableArtefact); + this.identifiableReader = identifiableReader; + } + + @Override + protected DataStructureDefinitionImpl createMaintainableArtefact() { + return new DataStructureDefinitionImpl(); + } + + @Override + public void readArtefact(JsonParser parser, DataStructureDefinitionImpl dataStructureDefinition) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.METADATA: + String metadataUrn = ReaderUtils.getStringJsonField(parser); + if (metadataUrn != null) { + dataStructureDefinition.setMetadataStructure(new MaintainableArtefactReference(metadataUrn)); + } + break; + case StructureUtils.DATA_STRUCTURE_COMPONENTS: + getDataStructureComponents(parser, dataStructureDefinition); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "DataStructureDefinition: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.DATA_STRUCTURES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getDataStructures().addAll(artefacts); + } + + private void getDataStructureComponents(JsonParser parser, DataStructureDefinitionImpl dataStructureDefinition) throws IOException { + parser.nextToken(); + if (ReaderUtils.isNullValue(parser)) { + return; + } + while (parser.nextToken() != JsonToken.END_OBJECT) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.ATTRIBUTE_LIST: + AttributeListReader attributeListReader = new AttributeListReader(); + AttributeDescriptorImpl attributeDescriptor = attributeListReader.getAttributeDescriptor(parser); + dataStructureDefinition.setAttributeDescriptor(attributeDescriptor); + break; + case StructureUtils.DIMENSION_LIST: + DimensionListReader dimensionListReader = new DimensionListReader(identifiableReader); + dataStructureDefinition.setDimensionDescriptor(dimensionListReader.getDimensionDescriptor(parser)); + break; + case StructureUtils.MEASURE_LIST: + MeasureListReader measureListReader = new MeasureListReader(); + dataStructureDefinition.setMeasureDescriptor(measureListReader.getMeasureDescriptor(parser)); + break; + case StructureUtils.GROUPS: + parser.nextToken(); + parser.skipChildren(); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "DataStructureComponent: " + fieldName); + } + } + } + +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DimensionListReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DimensionListReader.java new file mode 100644 index 0000000..994d5d2 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/DimensionListReader.java @@ -0,0 +1,145 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponent; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.infomodel.sdmx30.TimeDimensionImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; +import com.epam.jsdmx.serializer.util.DimensionUtil; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class DimensionListReader { + + private final IdentifiableReader identifiableReader; + + public DimensionListReader(IdentifiableReader identifiableReader) { + this.identifiableReader = identifiableReader; + } + + public DimensionDescriptorImpl getDimensionDescriptor(JsonParser parser) throws IOException { + parser.nextToken(); + if (ReaderUtils.isNullValue(parser)) { + return null; + } + DimensionDescriptorImpl dimensionDescriptor = new DimensionDescriptorImpl(); + List dimensionComponents = new ArrayList<>(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.DIMENSIONS: + List dimensions = ReaderUtils.getArray(parser, (this::getDimension)); + if (CollectionUtils.isNotEmpty(dimensions)) { + dimensionComponents.addAll(dimensions); + } + break; + case StructureUtils.TIME_DIMENSIONS: + List timeDimensions = ReaderUtils.getArray(parser, (this::getTimeDimension)); + if (CollectionUtils.isNotEmpty(timeDimensions)) { + dimensionComponents.addAll(timeDimensions); + } + break; + default: + identifiableReader.read(dimensionDescriptor, parser); + break; + } + } + + DimensionUtil.populateZeroBasedOrder(dimensionComponents); + + dimensionDescriptor.setComponents(dimensionComponents); + dimensionDescriptor.setId(StructureUtils.DIMENSION_DESCRIPTOR_ID); + return dimensionDescriptor; + } + + private TimeDimensionImpl getTimeDimension(JsonParser parser) { + try { + TimeDimensionImpl timeDimension = new TimeDimensionImpl(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.POSITION: + parser.nextToken(); + timeDimension.setOrder(parser.getIntValue()); + break; + case StructureUtils.TYPE: + parser.nextToken(); + break; + case StructureUtils.CONCEPT_IDENTITY: + String conceptIdentity = ReaderUtils.getStringJsonField(parser); + if (conceptIdentity != null) { + timeDimension.setConceptIdentity(new IdentifiableArtefactReferenceImpl(conceptIdentity)); + } + break; + case StructureUtils.LOCAL_REPRESENTATION: + timeDimension.setLocalRepresentation(getRepresentation(parser)); + break; + default: + identifiableReader.read(timeDimension, parser); + break; + } + } + return timeDimension; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private DimensionImpl getDimension(JsonParser parser) { + try { + DimensionImpl dimension = new DimensionImpl(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.POSITION: + parser.nextToken(); + dimension.setOrder(parser.getIntValue()); + break; + case StructureUtils.TYPE: + parser.nextToken(); + break; + case StructureUtils.CONCEPT_IDENTITY: + String conceptIdentity = ReaderUtils.getStringJsonField(parser); + if (conceptIdentity != null) { + dimension.setConceptIdentity(new IdentifiableArtefactReferenceImpl(conceptIdentity)); + } + break; + case StructureUtils.CONCEPT_ROLES: + List conceptRoles = ConceptRoleUtils.getConceptRoles(parser); + if (CollectionUtils.isNotEmpty(conceptRoles)) { + dimension.setConceptRoles(conceptRoles); + } + break; + case StructureUtils.LOCAL_REPRESENTATION: + dimension.setLocalRepresentation(getRepresentation(parser)); + break; + default: + identifiableReader.read(dimension, parser); + break; + } + } + return dimension; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private Representation getRepresentation(JsonParser parser) throws IOException { + RepresentationReader representationReader = new RepresentationReader(); + return representationReader.getRepresentations(parser); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GeoFeatureSetCodeReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GeoFeatureSetCodeReader.java new file mode 100644 index 0000000..ecea57e --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GeoFeatureSetCodeReader.java @@ -0,0 +1,18 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCodeImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; + +public class GeoFeatureSetCodeReader implements CodeReader { + @Override + public void readExtendedCodeFields(JsonParser parser, GeoFeatureSetCodeImpl code) throws IOException { + String currentName = parser.getCurrentName(); + if (StructureUtils.VALUE.equals(currentName)) { + code.setValue(ReaderUtils.getStringJsonField(parser)); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GeoGridCodelistReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GeoGridCodelistReader.java new file mode 100644 index 0000000..456cc57 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GeoGridCodelistReader.java @@ -0,0 +1,95 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.GeoGridCodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.GridCodeImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.apache.commons.collections.CollectionUtils; + +public class GeoGridCodelistReader extends MaintainableReader { + + private final CodelistExtensionReader codelistExtensionReader; + private final GridCodeReader gridCodeReader; + private final NameableReader nameableReader; + + Map codeWithParentId = new HashMap<>(); + + protected GeoGridCodelistReader(VersionableReader versionableArtefact, + CodelistExtensionReader codelistExtensionReader, + GridCodeReader gridCodeReader, + NameableReader nameableReader) { + super(versionableArtefact); + this.codelistExtensionReader = codelistExtensionReader; + this.gridCodeReader = gridCodeReader; + this.nameableReader = nameableReader; + } + + @Override + protected GeoGridCodelistImpl createMaintainableArtefact() { + return new GeoGridCodelistImpl(); + } + + @Override + public void readArtefact(JsonParser parser, GeoGridCodelistImpl geoGridCodelist) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.GEO_GRID_CODES: + List geoFeatureSetCodes = ReaderUtils.getArray(parser, (this::getGeoGridCodes)); + if (CollectionUtils.isNotEmpty(geoFeatureSetCodes)) { + geoGridCodelist.setItems(List.copyOf(geoFeatureSetCodes)); + } + break; + case StructureUtils.GEO_TYPE: + parser.nextToken(); + parser.nextToken(); + break; + case StructureUtils.CODE_LIST_EXTENSIONS: + parser.nextToken(); + List codeListExtensions = codelistExtensionReader.getCodeListExtensions(parser); + if (CollectionUtils.isNotEmpty(codeListExtensions)) { + geoGridCodelist.setExtensions(codeListExtensions); + } + break; + case StructureUtils.GRID_DEFINITION: + geoGridCodelist.setGridDefinition(ReaderUtils.getStringJsonField(parser)); + break; + case StructureUtils.IS_PARTIAL: + geoGridCodelist.setPartial(ReaderUtils.getBooleanJsonField(parser)); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "GeographicalCodelist: " + fieldName); + } + } + + private GridCodeImpl getGeoGridCodes(JsonParser parser) { + try { + return gridCodeReader.getCode(parser, new GridCodeImpl(), nameableReader, codeWithParentId); + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + @Override + protected String getName() { + return StructureUtils.GEO_GRID_CODELISTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getGeoGridCodelists().addAll(artefacts); + } + + @Override + protected void clean() { + codeWithParentId.clear(); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GeographicCodelistReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GeographicCodelistReader.java new file mode 100644 index 0000000..caadeea --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GeographicCodelistReader.java @@ -0,0 +1,93 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCode; +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeographicCodelistImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.apache.commons.collections.CollectionUtils; + +public class GeographicCodelistReader extends MaintainableReader { + + private final CodelistExtensionReader codelistExtensionReader; + private final GeoFeatureSetCodeReader geoFeatureSetCodeReader; + private final NameableReader nameableReader; + + Map codeWithParentId = new HashMap<>(); + + protected GeographicCodelistReader(VersionableReader versionableArtefact, + NameableReader nameableReader, + CodelistExtensionReader codelistExtensionReader, + GeoFeatureSetCodeReader geoFeatureSetCodeReader) { + super(versionableArtefact); + this.codelistExtensionReader = codelistExtensionReader; + this.nameableReader = nameableReader; + this.geoFeatureSetCodeReader = geoFeatureSetCodeReader; + } + + @Override + protected GeographicCodelistImpl createMaintainableArtefact() { + return new GeographicCodelistImpl(); + } + + @Override + public void readArtefact(JsonParser parser, GeographicCodelistImpl geographicCodelist) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.GEO_FEATURE_SET_CODES: + List geoFeatureSetCodes = ReaderUtils.getArray(parser, (this::getGeographicalCode)); + if (CollectionUtils.isNotEmpty(geoFeatureSetCodes)) { + geographicCodelist.setItems(List.copyOf(geoFeatureSetCodes)); + } + break; + case StructureUtils.GEO_TYPE: + parser.nextToken(); + parser.nextToken(); + break; + case StructureUtils.CODE_LIST_EXTENSIONS: + parser.nextToken(); + List codeListExtensions = codelistExtensionReader.getCodeListExtensions(parser); + if (CollectionUtils.isNotEmpty(codeListExtensions)) { + geographicCodelist.setExtensions(codeListExtensions); + } + break; + case StructureUtils.IS_PARTIAL: + geographicCodelist.setPartial(ReaderUtils.getBooleanJsonField(parser)); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "GeographicalCodelist: " + fieldName); + } + } + + private GeoFeatureSetCodeImpl getGeographicalCode(JsonParser parser) { + try { + return geoFeatureSetCodeReader.getCode(parser, new GeoFeatureSetCodeImpl(), nameableReader, codeWithParentId); + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + @Override + protected String getName() { + return StructureUtils.GEOGRAPHIC_CODELISTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getGeographicCodelists().addAll(artefacts); + } + + @Override + protected void clean() { + codeWithParentId.clear(); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GridCodeReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GridCodeReader.java new file mode 100644 index 0000000..453e745 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/GridCodeReader.java @@ -0,0 +1,19 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.GridCodeImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; + +public class GridCodeReader implements CodeReader { + + @Override + public void readExtendedCodeFields(JsonParser parser, GridCodeImpl code) throws IOException { + String currentName = parser.getCurrentName(); + if (StructureUtils.GEO_CELL.equals(currentName)) { + code.setGeoCell(ReaderUtils.getStringJsonField(parser)); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/HierarchyAssociationReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/HierarchyAssociationReader.java new file mode 100644 index 0000000..8af0815 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/HierarchyAssociationReader.java @@ -0,0 +1,60 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyAssociationImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; + +public class HierarchyAssociationReader extends MaintainableReader { + + public HierarchyAssociationReader(VersionableReader versionableReader) { + super(versionableReader); + } + + @Override + protected HierarchyAssociationImpl createMaintainableArtefact() { + return new HierarchyAssociationImpl(); + } + + @Override + public void readArtefact(JsonParser parser, HierarchyAssociationImpl hierarchyAssociation) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.LINKED_HIERARCHY: + String linkedHierarchy = ReaderUtils.getStringJsonField(parser); + if (linkedHierarchy != null) { + hierarchyAssociation.setLinkedHierarchy(new MaintainableArtefactReference(linkedHierarchy)); + } + break; + case StructureUtils.CONTEXT_OBJECT: + String contextObject = ReaderUtils.getStringJsonField(parser); + if (contextObject != null) { + hierarchyAssociation.setContextObject(new MaintainableArtefactReference(contextObject)); + } + break; + case StructureUtils.LINKED_OBJECT: + String linkedObject = ReaderUtils.getStringJsonField(parser); + if (linkedObject != null) { + hierarchyAssociation.setLinkedObject(new MaintainableArtefactReference(linkedObject)); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "HierarchyAssociation: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.HIERARCHY_ASSOCIATIONS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getHierarchyAssociations().addAll(artefacts); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/HierarchyReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/HierarchyReader.java new file mode 100644 index 0000000..c6e6140 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/HierarchyReader.java @@ -0,0 +1,229 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; + +import java.io.IOException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.BaseFacetImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodingFormat; +import com.epam.jsdmx.infomodel.sdmx30.CodingFormatImpl; +import com.epam.jsdmx.infomodel.sdmx30.FacetType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.HierarchicalCode; +import com.epam.jsdmx.infomodel.sdmx30.HierarchicalCodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.LevelImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class HierarchyReader extends MaintainableReader { + + public final IdentifiableReader identifiableReader; + + private final NameableReader nameableReader; + + public HierarchyReader(VersionableReader versionableArtefact, + IdentifiableReader identifiableReader, + NameableReader nameableReader) { + super(versionableArtefact); + this.identifiableReader = identifiableReader; + this.nameableReader = nameableReader; + } + + @Override + protected HierarchyImpl createMaintainableArtefact() { + return new HierarchyImpl(); + } + + @Override + public void readArtefact(JsonParser parser, HierarchyImpl hierarchy) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.HIERARCHICAL_CODES: + List hierarchicalCodes = ReaderUtils.getArray(parser, this::getHierarchicalCode); + if (CollectionUtils.isNotEmpty(hierarchicalCodes)) { + hierarchy.setCodes(hierarchicalCodes); + } + break; + case StructureUtils.HAS_FORMAT_LEVELS: + boolean hasFormatLevels = ReaderUtils.getBooleanJsonField(parser); + hierarchy.setHasFormalLevels(hasFormatLevels); + break; + case StructureUtils.LEVEL: + hierarchy.setLevel(getLevel(parser)); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "Hierarchy: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.HIERARCHIES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getHierarchies().addAll(artefacts); + } + + private LevelImpl getLevel(JsonParser parser) throws IOException { + parser.nextToken(); + if (parser.currentToken() + .equals(JsonToken.START_OBJECT) && parser.nextToken() + .equals(JsonToken.END_OBJECT)) { + return null; + } + LevelImpl level = new LevelImpl(); + while (!JsonToken.END_OBJECT.equals(parser.currentToken())) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.LEVEL: + level.setChild(getLevel(parser)); + parser.nextToken(); + break; + case StructureUtils.CODING_FORMAT: + level.setCodeFormat(getCodingFormats(parser)); + parser.nextToken(); + break; + default: + nameableReader.read(level, parser); + parser.nextToken(); + break; + } + } + return level; + } + + private List getCodingFormats(JsonParser parser) throws IOException { + List codingFormats = new ArrayList<>(); + parser.nextToken(); + if (parser.currentToken() + .equals(JsonToken.START_OBJECT) && parser.nextToken() + .equals(JsonToken.END_OBJECT)) { + return List.of(); + } + while (!JsonToken.END_OBJECT.equals(parser.currentToken())) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.DATA_TYPE: + String dataType = ReaderUtils.getStringJsonField(parser); + if (dataType != null) { + CodingFormatImpl codingFormat = new CodingFormatImpl(); + codingFormat.setCodingFormat(new BaseFacetImpl(FacetValueType.fromValue(dataType))); + codingFormats.add(codingFormat); + } + parser.nextToken(); + break; + case StructureUtils.IS_SEQUENCE: + codingFormats.add(setFacet(FacetType.IS_SEQUENCE, parser)); + parser.nextToken(); + break; + case StructureUtils.INTERVAL: + codingFormats.add(setFacet(FacetType.INTERVAL, parser)); + parser.nextToken(); + break; + case StructureUtils.START_VALUE: + codingFormats.add(setFacet(FacetType.START_VALUE, parser)); + break; + case StructureUtils.END_VALUE: + codingFormats.add(setFacet(FacetType.END_VALUE, parser)); + parser.nextToken(); + break; + case StructureUtils.MIN_LENGTH: + codingFormats.add(setFacet(FacetType.MIN_LENGTH, parser)); + parser.nextToken(); + break; + case StructureUtils.MAX_LENGTH: + codingFormats.add(setFacet(FacetType.MAX_LENGTH, parser)); + parser.nextToken(); + break; + case StructureUtils.MIN_VALUE: + codingFormats.add(setFacet(FacetType.MIN_VALUE, parser)); + parser.nextToken(); + break; + case StructureUtils.MAX_VALUE: + codingFormats.add(setFacet(FacetType.MAX_VALUE, parser)); + parser.nextToken(); + break; + case StructureUtils.PATTERN: + codingFormats.add(setFacet(FacetType.PATTERN, parser)); + parser.nextToken(); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "CodingFormat:" + fieldName); + } + } + return codingFormats; + } + + private CodingFormatImpl setFacet(FacetType startValue, JsonParser parser) throws IOException { + BaseFacetImpl baseFacetStartValue = new BaseFacetImpl(); + baseFacetStartValue.setType(startValue); + baseFacetStartValue.setValue(ReaderUtils.getFieldAsString(parser)); + CodingFormatImpl codingFormat = new CodingFormatImpl(); + codingFormat.setCodingFormat(baseFacetStartValue); + return codingFormat; + } + + private HierarchicalCode getHierarchicalCode(JsonParser parser) { + try { + HierarchicalCodeImpl hierarchicalCode = new HierarchicalCodeImpl(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.HIERARCHICAL_CODES: + parser.nextToken(); + setHierarchicalCodes(parser, hierarchicalCode); + break; + case StructureUtils.CODE: + String code = ReaderUtils.getStringJsonField(parser); + if (code != null) { + hierarchicalCode.setCode(new IdentifiableArtefactReferenceImpl(code)); + } + break; + case StructureUtils.VALID_TO: + Instant validTo = ReaderUtils.getInstantObj(parser); + if (validTo != null) { + hierarchicalCode.setValidTo(validTo); + } + break; + case StructureUtils.VALID_FROM: + Instant validFrom = ReaderUtils.getInstantObj(parser); + if (validFrom != null) { + hierarchicalCode.setValidFrom(validFrom); + } + break; + case StructureUtils.LEVEL: + hierarchicalCode.setLevelId(ReaderUtils.getStringJsonField(parser)); + break; + default: + identifiableReader.read(hierarchicalCode, parser); + break; + } + } + return hierarchicalCode; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private void setHierarchicalCodes(JsonParser parser, HierarchicalCodeImpl hierarchicalCode) throws IOException { + List hierarchicalCodes = ReaderUtils.getArray(parser, this::getHierarchicalCode); + if (CollectionUtils.isNotEmpty(hierarchicalCodes)) { + hierarchicalCode.setHierarchicalCodes(hierarchicalCodes); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/IdentifiableReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/IdentifiableReader.java new file mode 100644 index 0000000..4b74d15 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/IdentifiableReader.java @@ -0,0 +1,29 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; + +public class IdentifiableReader { + + private final AnnotableReader annotableReader; + + public IdentifiableReader(AnnotableReader annotableReader) { + this.annotableReader = annotableReader; + } + + public IdentifiableArtefact read(IdentifiableArtefactImpl identifiableArtefact, JsonParser parser) throws IOException { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + if (StructureUtils.ID.equals(fieldName)) { + identifiableArtefact.setId(ReaderUtils.getStringJsonField(parser)); + } else { + annotableReader.read(identifiableArtefact, parser); + } + return identifiableArtefact; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ItemMapReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ItemMapReader.java new file mode 100644 index 0000000..08079c9 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ItemMapReader.java @@ -0,0 +1,59 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getFieldAsString; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getInstantObj; + +import java.io.IOException; +import java.util.Optional; + +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.infomodel.sdmx30.ItemMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.lang3.StringUtils; + +public interface ItemMapReader { + + default ItemMap getItemMap(JsonParser parser) { + ItemMapImpl itemMap = new ItemMapImpl(); + try { + while (parser.nextToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.SOURCE_VALUE: + itemMap.setSource(getFieldAsString(parser)); + break; + case StructureUtils.TARGET_VALUE: + itemMap.setTarget(getFieldAsString(parser)); + break; + case StructureUtils.VALID_FROM: + itemMap.setValidFrom(getInstantObj(parser)); + break; + case StructureUtils.VALID_TO: + itemMap.setValidTo(getInstantObj(parser)); + break; + default: + AnnotableReader annotableReader = new AnnotableReader(); + annotableReader.read(itemMap, parser); + break; + } + } + return itemMap; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + default Optional getTargetSource(JsonParser parser) throws IOException { + String target = ReaderUtils.getStringJsonField(parser); + if (StringUtils.isBlank(target)) { + return Optional.empty(); + } + return Optional.of(new MaintainableArtefactReference(target)); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/JsonReaderFactory.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/JsonReaderFactory.java new file mode 100644 index 0000000..f0a03d7 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/JsonReaderFactory.java @@ -0,0 +1,254 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactImpl; + +public final class JsonReaderFactory { + + private JsonReaderFactory() { + } + + public static DataReader newInstance() { + return new DataReader(readers()); + } + + private static AnnotableReader getAnnotableReader() { + return new AnnotableReader(); + } + + private static IdentifiableReader getIdentifiableReader() { + return new IdentifiableReader(getAnnotableReader()); + } + + private static NameableReader getNameableReader() { + return new NameableReader(getIdentifiableReader()); + } + + private static VersionableReader getVersionableReader() { + return new VersionableReader(getNameableReader()); + } + + private static ContactReader getContactReader() { + return new ContactReader(); + } + + private static OrganisationReader getOrganisationReader() { + return new OrganisationReader(getContactReader(), getNameableReader()); + } + + private static MemberSelectionReader getMemberSelectionReader() { + return new MemberSelectionReader(); + } + + private static AgencySchemeReader getAgencySchemeReader() { + return new AgencySchemeReader(getVersionableReader(), getOrganisationReader()); + } + + private static CategorisationReader getCategorisationReader() { + return new CategorisationReader(getVersionableReader()); + } + + private static CategorySchemeMapReader getCategorySchemeMapReader() { + return new CategorySchemeMapReader(getVersionableReader()); + } + + private static CategorySchemeReader getCategorySchemeReader() { + return new CategorySchemeReader(getVersionableReader(), getNameableReader()); + } + + private static CodelistReader getCodelistReader() { + return new CodelistReader(getVersionableReader(), getNameableReader(), getCodelistExtensionReader(), getCodeImplReader()); + } + + private static CodeImplReader getCodeImplReader() { + return new CodeImplReader(); + } + + private static CodelistExtensionReader getCodelistExtensionReader() { + return new CodelistExtensionReader(); + } + + private static GeoFeatureSetCodeReader getGeoFeatureSetCodeReader() { + return new GeoFeatureSetCodeReader(); + } + + private static GridCodeReader getGridCodeReader() { + return new GridCodeReader(); + } + + private static ConceptSchemeMapReader getConceptSchemeMapReader() { + return new ConceptSchemeMapReader(getVersionableReader()); + } + + private static ConceptSchemeReader getConceptSchemeReader() { + return new ConceptSchemeReader(getVersionableReader(), getNameableReader()); + } + + private static DataConsumerSchemeReader getDataConsumerSchemeReader() { + return new DataConsumerSchemeReader(getVersionableReader(), getOrganisationReader()); + } + + private static DataFlowReader getDataflowReader() { + return new DataFlowReader(getVersionableReader()); + } + + private static DataProviderSchemeReader getDataProviderSchemeReader() { + return new DataProviderSchemeReader(getVersionableReader(), getOrganisationReader()); + } + + private static DataStructureDefinitionReader getDataStructureDefinitionReader() { + return new DataStructureDefinitionReader( + getVersionableReader(), + getIdentifiableReader() + ); + } + + private static HierarchyAssociationReader getHierarchyAssociationReader() { + return new HierarchyAssociationReader(getVersionableReader()); + } + + private static HierarchyReader getHierarchyReader() { + return new HierarchyReader(getVersionableReader(), getIdentifiableReader(), getNameableReader()); + } + + private static MetadataConstraintReader getMetadataConstraintReader() { + return new MetadataConstraintReader(getVersionableReader(), getMemberSelectionReader(), getReleaseCalendarReader()); + } + + private static ReleaseCalendarReader getReleaseCalendarReader() { + return new ReleaseCalendarReader(); + } + + private static MetadataFlowReader getMetadataflowReader() { + return new MetadataFlowReader(getVersionableReader()); + } + + private static MetadataProviderSchemeReader getMetadataProviderSchemeReader() { + return new MetadataProviderSchemeReader(getVersionableReader(), getOrganisationReader()); + } + + private static MetadataProvisionAgreementReader getMetadataProvisionAgreementReader() { + return new MetadataProvisionAgreementReader(getVersionableReader()); + } + + private static MetaDataStructureDefinitionReader getMetadataStructureDefinitionReader() { + return new MetaDataStructureDefinitionReader( + getVersionableReader(), + getIdentifiableReader() + ); + } + + private static OrganisationSchemeMapReader getOrganisationSchemeMapReader() { + return new OrganisationSchemeMapReader(getVersionableReader()); + } + + private static OrganisationUnitSchemeReader getOrganisationUnitSchemeReader() { + return new OrganisationUnitSchemeReader(getVersionableReader(), getOrganisationReader()); + } + + private static ProcessReader getProcessReader() { + return new ProcessReader( + getVersionableReader(), + getNameableReader(), + getAnnotableReader(), + getIdentifiableReader() + ); + } + + private static ProvisionAgreementReader getProvisionAgreementReader() { + return new ProvisionAgreementReader(getVersionableReader()); + } + + private static ReportingTaxonomyReader getReportingTaxonomyReader() { + return new ReportingTaxonomyReader(getVersionableReader(), getNameableReader()); + } + + private static ReportingTaxonomyMapReader getReportingTaxonomyMapReader() { + return new ReportingTaxonomyMapReader(getVersionableReader()); + } + + private static RepresentationMapReader getRepresentationMapReader() { + return new RepresentationMapReader(getVersionableReader()); + } + + private static StructureMapReader getStructureMapReader() { + return new StructureMapReader( + getVersionableReader(), + getIdentifiableReader(), + getAnnotableReader() + ); + } + + private static ValueListReader getValueListReader() { + return new ValueListReader( + getVersionableReader(), + getAnnotableReader() + ); + } + + private static DataKeySetReader getDataKeySetReader() { + return new DataKeySetReader(getAnnotableReader(), getMemberSelectionReader()); + } + + private static CubeRegionReader getCubeRegionReader() { + return new CubeRegionReader(getMemberSelectionReader(), getAnnotableReader()); + } + + private static DataConstraintReader getDataConstraintsReader() { + return new DataConstraintReader(getVersionableReader(), getReleaseCalendarReader(), getDataKeySetReader(), getCubeRegionReader()); + } + + private static GeographicCodelistReader getGeographicCodelistReader() { + return new GeographicCodelistReader( + getVersionableReader(), + getNameableReader(), + getCodelistExtensionReader(), + getGeoFeatureSetCodeReader() + ); + } + + private static GeoGridCodelistReader getGeoGridCodelistReader() { + return new GeoGridCodelistReader( + getVersionableReader(), + getCodelistExtensionReader(), + getGridCodeReader(), + getNameableReader() + ); + } + + private static List> readers() { + return List.of( + getAgencySchemeReader(), + getCategorisationReader(), + getCategorySchemeReader(), + getCategorySchemeMapReader(), + getCodelistReader(), + getConceptSchemeReader(), + getConceptSchemeMapReader(), + getDataConstraintsReader(), + getDataConsumerSchemeReader(), + getDataProviderSchemeReader(), + getDataStructureDefinitionReader(), + getDataflowReader(), + getHierarchyReader(), + getHierarchyAssociationReader(), + getMetadataConstraintReader(), + getMetadataProviderSchemeReader(), + getMetadataProvisionAgreementReader(), + getMetadataStructureDefinitionReader(), + getMetadataflowReader(), + getOrganisationSchemeMapReader(), + getOrganisationUnitSchemeReader(), + getProcessReader(), + getProvisionAgreementReader(), + getReportingTaxonomyReader(), + getReportingTaxonomyMapReader(), + getRepresentationMapReader(), + getStructureMapReader(), + getValueListReader(), + getGeographicCodelistReader(), + getGeoGridCodelistReader() + ); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/JsonRuntimeException.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/JsonRuntimeException.java new file mode 100644 index 0000000..07d2b42 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/JsonRuntimeException.java @@ -0,0 +1,11 @@ +package com.epam.jsdmx.json20.structure.reader; + +public class JsonRuntimeException extends RuntimeException { + public JsonRuntimeException(String message) { + super(message); + } + + public JsonRuntimeException(Throwable cause) { + super(cause); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/JsonStructureReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/JsonStructureReader.java new file mode 100644 index 0000000..999f7d2 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/JsonStructureReader.java @@ -0,0 +1,78 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.io.InputStream; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.serializer.sdmx30.common.DataLocation; +import com.epam.jsdmx.serializer.sdmx30.common.Header; +import com.epam.jsdmx.serializer.sdmx30.structure.StructureReader; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import lombok.extern.slf4j.Slf4j; + +/** + * Streaming deserialization for json (2.0) + */ +@Slf4j +public class JsonStructureReader implements StructureReader { + + private final DataReader dataReader; + private final MetaReader metaReader; + + public JsonStructureReader(DataReader dataReader, MetaReader metaReader) { + this.dataReader = dataReader; + this.metaReader = metaReader; + } + + @Override + public ArtefactsImpl read(DataLocation location) { + final InputStream inputStream = location.inputStream(); + JsonFactory factory = new JsonFactory(); + ArtefactsImpl artefacts = new ArtefactsImpl(); + try (JsonParser parser = factory.createParser(inputStream)) { + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case "data": + parser.nextToken(); + artefacts = getData(parser); + break; + case "meta": + parser.nextToken(); + getHeader(parser); + break; + case "error": + parser.nextToken(); + break; + default: + throw new IllegalArgumentException("Not correct structure: " + fieldName); + } + } + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + return artefacts; + } + + private Header getHeader(JsonParser parser) throws IOException { + return metaReader.read(parser); + } + + private ArtefactsImpl getData(JsonParser parser) throws IOException { + return dataReader.read(parser); + } + + public ArtefactsImpl readAndClose(DataLocation location) { + final InputStream inputStream = location.inputStream(); + try (inputStream) { + return read(location); + } catch (IOException e) { + log.error(e.getMessage()); + } + return null; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MaintainableReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MaintainableReader.java new file mode 100644 index 0000000..c58dbc9 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MaintainableReader.java @@ -0,0 +1,82 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getStringJsonField; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class MaintainableReader { + + private final VersionableReader versionableArtefact; + + protected MaintainableReader(VersionableReader versionableArtefact) { + this.versionableArtefact = versionableArtefact; + } + + protected abstract T createMaintainableArtefact(); + + public abstract void readArtefact(JsonParser parser, T maintainableArtefact) throws IOException; + + public T read(JsonParser parser) throws IOException { + T maintainable = createMaintainableArtefact(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + if (!checkIsNotEmptyObjectAndSkipUntilFieldName(parser)) { + return null; + } + String fieldname = parser.getCurrentName(); + switch (fieldname) { + case StructureUtils.ID: + case StructureUtils.ANNOTATIONS: + case StructureUtils.VERSION: + case StructureUtils.VALID_TO: + case StructureUtils.VALID_FROM: + case StructureUtils.NAMES: + case StructureUtils.DESCRIPTIONS: + case StructureUtils.DESCRIPTION: + case StructureUtils.NAME: + versionableArtefact.read(maintainable, parser); + break; + case StructureUtils.AGENCY_ID: + maintainable.setOrganizationId(getStringJsonField(parser)); + break; + case StructureUtils.LINKS: + parser.nextToken(); + parser.skipChildren(); + break; + case StructureUtils.IS_EXTERNAL_REFERENCE: + parser.nextToken(); + break; + default: + readArtefact(parser, maintainable); + } + } + return maintainable; + } + + public MaintainableArtefactImpl readAndClose(JsonParser parser) throws IOException { + try (parser) { + return read(parser); + } catch (IOException e) { + log.error(e.getMessage()); + throw e; + } + } + + protected abstract String getName(); + + protected abstract void setArtefacts(Artefacts artefact, Set artefacts); + + protected void clean() { + // individual for each artefact + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MeasureListReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MeasureListReader.java new file mode 100644 index 0000000..c077416 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MeasureListReader.java @@ -0,0 +1,88 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.Measure; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureImpl; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class MeasureListReader { + + private final IdentifiableReader identifiableReader = new IdentifiableReader( + new AnnotableReader()); + + public MeasureDescriptorImpl getMeasureDescriptor(JsonParser parser) throws IOException { + parser.nextToken(); + if (ReaderUtils.isNullValue(parser)) { + return null; + } + MeasureDescriptorImpl measureDescriptor = new MeasureDescriptorImpl(); + List measures = new ArrayList<>(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + if (StructureUtils.MEASURES.equals(fieldName)) { + List measureList = ReaderUtils.getArray(parser, this::getMeasure); + if (CollectionUtils.isNotEmpty(measureList)) { + measures.addAll(measureList); + } + } else { + identifiableReader.read(measureDescriptor, parser); + } + } + measureDescriptor.setComponents(measures); + measureDescriptor.setId(StructureUtils.MEASURE_DESCRIPTOR_ID); + return measureDescriptor; + } + + private Measure getMeasure(JsonParser parser) { + try { + MeasureImpl measure = new MeasureImpl(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.IS_MANDATORY: + parser.nextToken(); + break; + case StructureUtils.CONCEPT_IDENTITY: + String conceptIdentity = ReaderUtils.getStringJsonField(parser); + if (conceptIdentity != null) { + measure.setConceptIdentity(new IdentifiableArtefactReferenceImpl(conceptIdentity)); + } + break; + case StructureUtils.CONCEPT_ROLES: + List conceptRoles = ConceptRoleUtils.getConceptRoles(parser); + if (CollectionUtils.isNotEmpty(conceptRoles)) { + measure.setConceptRoles(conceptRoles); + } + break; + case StructureUtils.LOCAL_REPRESENTATION: + measure.setLocalRepresentation(getRepresentation(parser)); + break; + default: + identifiableReader.read(measure, parser); + break; + } + } + return measure; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private Representation getRepresentation(JsonParser parser) throws IOException { + RepresentationReader representationReader = new RepresentationReader(); + return representationReader.getRepresentations(parser); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MemberSelectionReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MemberSelectionReader.java new file mode 100644 index 0000000..db57dfd --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MemberSelectionReader.java @@ -0,0 +1,196 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getBooleanJsonField; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getFieldAsString; + +import java.io.IOException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.AfterPeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.BeforePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.CascadeValue; +import com.epam.jsdmx.infomodel.sdmx30.LocalisedMemberValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.RangePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.SelectionValue; +import com.epam.jsdmx.infomodel.sdmx30.TimeRangePeriodImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class MemberSelectionReader { + + public MemberSelection getMemberSelection(JsonParser parser) { + try { + MemberSelectionImpl memberSelection = new MemberSelectionImpl(); + List selectionValues = new ArrayList<>(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.INCLUDE: + memberSelection.setIncluded(getBooleanJsonField(parser)); + break; + case StructureUtils.ID: + memberSelection.setComponentId(getFieldAsString(parser)); + break; + case StructureUtils.REMOVE_PREFIX: + memberSelection.setRemovePrefix(getBooleanJsonField(parser)); + break; + case StructureUtils.TIME_RANGE: + List timeRanges = getTimeRanges(parser); + if (CollectionUtils.isNotEmpty(timeRanges)) { + selectionValues.addAll(timeRanges); + } + break; + case StructureUtils.VALUES: + List values = ReaderUtils.getArray(parser, (this::getMemberValue)); + selectionValues.addAll(values); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "MemberSelection: " + fieldName); + } + } + memberSelection.setSelectionValues(selectionValues); + return memberSelection; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + public SelectionValue getMemberValue(JsonParser parser) { + try { + MemberValueImpl memberValue = new MemberValueImpl(); + LocalisedMemberValueImpl localMemberValue = new LocalisedMemberValueImpl(); + parser.nextToken(); + if (parser.currentToken() + .equals(JsonToken.START_OBJECT) && parser.nextToken() + .equals(JsonToken.END_OBJECT)) { + return null; + } + while (parser.currentToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.VALUE: + String value = getFieldAsString(parser); + memberValue.setValue(value); + localMemberValue.setValue(value); + parser.nextToken(); + break; + case StructureUtils.LANG: + String lang = getFieldAsString(parser); + if (lang != null) { + localMemberValue.setLocale(lang); + } + parser.nextToken(); + break; + case StructureUtils.CASCADE_VALUES: + String cascadeValString = getFieldAsString(parser); + if (cascadeValString != null) { + CascadeValue cascadeValue = StructureUtils.STRING_CASCADE_VALUE_TYPE.get(cascadeValString); + memberValue.setCascadeValue(cascadeValue); + } + parser.nextToken(); + break; + case StructureUtils.VALID_FROM: + Instant validFrom = ReaderUtils.getInstantObj(parser); + if (validFrom != null) { + memberValue.setValidFrom(validFrom); + localMemberValue.setValidFrom(validFrom); + } + parser.nextToken(); + break; + case StructureUtils.VALID_TO: + Instant validTo = ReaderUtils.getInstantObj(parser); + if (validTo != null) { + memberValue.setValidTo(validTo); + localMemberValue.setValidTo(validTo); + } + parser.nextToken(); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "MemberValue: " + fieldName); + } + } + return localMemberValue.getLocale() != null ? localMemberValue : memberValue; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + public List getTimeRanges(JsonParser parser) { + try { + parser.nextToken(); + if (parser.currentToken() + .equals(JsonToken.START_OBJECT) && parser.nextToken() + .equals(JsonToken.END_OBJECT)) { + return List.of(); + } + List timeRanges = new ArrayList<>(); + RangePeriodImpl rangePeriod = new RangePeriodImpl(); + while (parser.currentToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.AFTER_PERIOD: + AfterPeriodImpl afterPeriod = new AfterPeriodImpl(); + setTimeRange(parser, afterPeriod); + timeRanges.add(afterPeriod); + parser.nextToken(); + break; + case StructureUtils.BEFORE_PERIOD: + BeforePeriodImpl beforePeriod = new BeforePeriodImpl(); + setTimeRange(parser, beforePeriod); + timeRanges.add(beforePeriod); + parser.nextToken(); + break; + case StructureUtils.START_PERIOD: + TimeRangePeriodImpl startPeriod = new TimeRangePeriodImpl(); + setTimeRange(parser, startPeriod); + rangePeriod.setStartPeriod(startPeriod); + parser.nextToken(); + break; + case StructureUtils.END_PERIOD: + TimeRangePeriodImpl endPeriod = new TimeRangePeriodImpl(); + setTimeRange(parser, endPeriod); + rangePeriod.setEndPeriod(endPeriod); + parser.nextToken(); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "TimeRange: " + fieldName); + } + } + if (!(rangePeriod.getStartPeriod() == null && rangePeriod.getEndPeriod() == null)) { + timeRanges.add(rangePeriod); + } + return timeRanges; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private void setTimeRange(JsonParser parser, TimeRangePeriodImpl timeRange) throws IOException { + while (parser.nextToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.IS_INCLUSIVE: + timeRange.setInclusive(getBooleanJsonField(parser)); + break; + case StructureUtils.PERIOD: + timeRange.setPeriod(getFieldAsString(parser)); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + " TimeRange: " + fieldName); + } + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetaDataStructureDefinitionReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetaDataStructureDefinitionReader.java new file mode 100644 index 0000000..464cd4b --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetaDataStructureDefinitionReader.java @@ -0,0 +1,148 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttribute; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinitionImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class MetaDataStructureDefinitionReader extends MaintainableReader { + + private final IdentifiableReader identifiableReader; + + public MetaDataStructureDefinitionReader(VersionableReader versionableArtefact, IdentifiableReader identifiableReader) { + super(versionableArtefact); + this.identifiableReader = identifiableReader; + } + + @Override + protected MetadataStructureDefinitionImpl createMaintainableArtefact() { + return new MetadataStructureDefinitionImpl(); + } + + @Override + public void readArtefact(JsonParser parser, MetadataStructureDefinitionImpl dataStructureDefinition) throws IOException { + String fieldName = parser.getCurrentName(); + if (StructureUtils.METADATA_STRUCTURE_COMPONENTS.equals(fieldName)) { + dataStructureDefinition.setAttributeDescriptor(getAttributeDescriptor(parser)); + } else { + parser.skipChildren(); + } + } + + @Override + protected String getName() { + return StructureUtils.METADATA_STRUCTURES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getMetadataStructureDefinitions().addAll(artefacts); + } + + private MetadataAttributeDescriptorImpl getAttributeDescriptor(JsonParser parser) throws IOException { + parser.nextToken(); + var metadataAttributeDescriptor = new MetadataAttributeDescriptorImpl(); + if (parser.currentToken() + .equals(JsonToken.START_OBJECT) && parser.nextToken() + .equals(JsonToken.END_OBJECT)) { + return null; + } + while (parser.currentToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + if (StructureUtils.METADATA_ATTRIBUTE_LIST.equals(fieldName)) { + metadataAttributeDescriptor = getMetadataAttribute(parser); + parser.nextToken(); + } else { + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "MetadataAttributeDescriptor: " + fieldName); + } + } + return metadataAttributeDescriptor; + } + + private MetadataAttributeDescriptorImpl getMetadataAttribute(JsonParser parser) throws IOException { + parser.nextToken(); + MetadataAttributeDescriptorImpl metadataAttributeDescriptor = new MetadataAttributeDescriptorImpl(); + if (parser.currentToken() + .equals(JsonToken.START_OBJECT) && parser.nextToken() + .equals(JsonToken.END_OBJECT)) { + return null; + } + while (parser.currentToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + if (StructureUtils.METADATA_ATTRIBUTES.equals(fieldName)) { + List metadataComponents = ReaderUtils.getArray(parser, this::getComponent); + if (CollectionUtils.isNotEmpty(metadataComponents)) { + metadataAttributeDescriptor.setComponents(metadataComponents); + } + } else { + identifiableReader.read(metadataAttributeDescriptor, parser); + } + parser.nextToken(); + } + return metadataAttributeDescriptor; + } + + private MetadataAttributeImpl getComponent(JsonParser parser) { + try { + MetadataAttributeImpl metadataAttribute = new MetadataAttributeImpl(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.CONCEPT_IDENTITY: + metadataAttribute.setConceptIdentity(getConceptIdentity(parser)); + break; + case StructureUtils.MIN_OCCURS: + metadataAttribute.setMinOccurs(ReaderUtils.getIntJsonField(parser)); + break; + case StructureUtils.MAX_OCCURS: + metadataAttribute.setMaxOccurs(ReaderUtils.getIntJsonField(parser)); + break; + case StructureUtils.LOCAL_REPRESENTATION: + RepresentationReader representationReader = new RepresentationReader(); + metadataAttribute.setLocalRepresentation(representationReader.getRepresentations(parser)); + break; + case StructureUtils.IS_PRESENTATIONAL: + boolean isPresentational = ReaderUtils.getBooleanJsonField(parser); + metadataAttribute.setPresentational(isPresentational); + break; + case StructureUtils.METADATA_ATTRIBUTES: + List metadataComponents = ReaderUtils.getArray(parser, this::getComponent); + if (CollectionUtils.isNotEmpty(metadataComponents)) { + metadataAttribute.setHierarchy(metadataComponents); + } + break; + default: + identifiableReader.read(metadataAttribute, parser); + break; + } + } + return metadataAttribute; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private IdentifiableArtefactReferenceImpl getConceptIdentity(JsonParser parser) throws IOException { + String conceptIdentity = ReaderUtils.getStringJsonField(parser); + if (conceptIdentity != null) { + return new IdentifiableArtefactReferenceImpl(conceptIdentity); + } + return null; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetaReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetaReader.java new file mode 100644 index 0000000..8eba7d0 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetaReader.java @@ -0,0 +1,107 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; +import com.epam.jsdmx.serializer.sdmx30.common.Header; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.lang3.LocaleUtils; + +public class MetaReader { + + public Header read(JsonParser parser) throws IOException { + Header header = new Header(); + if (JsonToken.START_OBJECT.equals(parser.currentToken()) + && JsonToken.END_OBJECT.equals(parser.nextToken())) { + return null; + } + while (!JsonToken.END_OBJECT.equals(parser.currentToken())) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String currentParserName = parser.getCurrentName(); + switch (currentParserName) { + case StructureUtils.SCHEMA: + String schemaURI = ReaderUtils.getStringJsonField(parser); + if (schemaURI != null) { + try { + URI uri = new URI(schemaURI); + header.setSchema(uri); + } catch (URISyntaxException e) { + throw new MalformedURLException(e.getMessage()); + } + + } + break; + case StructureUtils.ID: + header.setId(ReaderUtils.getStringJsonField(parser)); + break; + case StructureUtils.TEST: + header.setTest(ReaderUtils.getBooleanJsonField(parser)); + break; + case StructureUtils.PREPARED: + header.setPrepared(ReaderUtils.getInstantObj(parser)); + break; + case StructureUtils.CONTENT_LANGUAGES: + List contentLangs = ReaderUtils.getListStrings(parser); + List locales = contentLangs.stream() + .filter(Objects::nonNull) + .map(LocaleUtils::toLocale) + .collect(Collectors.toList()); + header.setContentLanguages(locales); + break; + case StructureUtils.NAME: + String name = ReaderUtils.getStringJsonField(parser); + if (name != null) { + header.setName(new InternationalString(name)); + } + break; + case StructureUtils.SENDER: + header.setSender(getParty(parser)); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + + "Header: " + currentParserName); + } + parser.nextToken(); + } + return header; + } + + private Party getParty(JsonParser parser) throws IOException { + if (JsonToken.START_OBJECT.equals(parser.currentToken()) + && JsonToken.END_OBJECT.equals(parser.nextToken())) { + return null; + } + Party party = new Party(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String currentParserName = parser.getCurrentName(); + switch (currentParserName) { + case StructureUtils.ID: + party.setId(ReaderUtils.getStringJsonField(parser)); + break; + case StructureUtils.NAME: + party.setName( + new InternationalString( + ReaderUtils.getStringJsonField(parser))); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + + "Party: " + currentParserName); + } + } + return party; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataConstraintReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataConstraintReader.java new file mode 100644 index 0000000..ca68212 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataConstraintReader.java @@ -0,0 +1,153 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getStringJsonField; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ConstraintRoleType; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.MetadataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataTargetRegion; +import com.epam.jsdmx.infomodel.sdmx30.MetadataTargetRegionImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class MetadataConstraintReader extends MaintainableReader { + + private final MemberSelectionReader memberSelectionReader; + private final ReleaseCalendarReader releaseCalendarReader; + + public MetadataConstraintReader(VersionableReader versionableArtefact, + MemberSelectionReader memberSelectionReader, + ReleaseCalendarReader releaseCalendarReader) { + super(versionableArtefact); + this.memberSelectionReader = memberSelectionReader; + this.releaseCalendarReader = releaseCalendarReader; + } + + @Override + protected MetadataConstraintImpl createMaintainableArtefact() { + return new MetadataConstraintImpl(); + } + + @Override + public void readArtefact(JsonParser parser, MetadataConstraintImpl metadataConstraint) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.ROLE: + metadataConstraint.setConstraintRoleType(ConstraintRoleType.ALLOWABLE_CONTENT); + break; + case StructureUtils.METADATA_TARGET_REGIONS: + List metadataTargetRegions = ReaderUtils.getArray(parser, (this::getMetadataTargetRegion)); + if (CollectionUtils.isNotEmpty(metadataTargetRegions)) { + metadataConstraint.setMetadataTargetRegions(metadataTargetRegions); + } + break; + case StructureUtils.RELEASE_CALENDAR: + metadataConstraint.setReleaseCalendar(releaseCalendarReader.getReleaseCalendar(parser)); + break; + case StructureUtils.CONSTRAINT_ATTACHMENT: + metadataConstraint.setConstrainedArtefacts(getConstraintAttachment(parser)); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "MetadataConstraint: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.METADATA_CONSTRAINTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getMetadataConstraints().addAll(artefacts); + } + + private List getConstraintAttachment(JsonParser parser) throws IOException { + parser.nextToken(); + List artefactReferences = new ArrayList<>(); + if (parser.currentToken() + .equals(JsonToken.START_OBJECT) && parser.nextToken() + .equals(JsonToken.END_OBJECT)) { + return Collections.emptyList(); + } + while (parser.currentToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.METADATA_PROVIDER: + String metadataProvider = getStringJsonField(parser); + if (metadataProvider != null) { + artefactReferences.add(new IdentifiableArtefactReferenceImpl(metadataProvider)); + } + parser.nextToken(); + break; + case StructureUtils.METADATA_SETS: + case StructureUtils.METADATA_STRUCTURES: + case StructureUtils.METADATAFLOWS: + case StructureUtils.METADATA_PROVISION_AGREEMENTS: + List metadataSets = ReaderUtils.getListStrings(parser); + List references = metadataSets.stream() + .filter(Objects::nonNull) + .map(IdentifiableArtefactReferenceImpl::new) + .collect(Collectors.toList()); + artefactReferences.addAll(references); + parser.nextToken(); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + " ConstraintAttachment: " + fieldName); + } + } + return artefactReferences; + } + + private MetadataTargetRegion getMetadataTargetRegion(JsonParser parser) { + try { + MetadataTargetRegionImpl metadataTargetRegion = new MetadataTargetRegionImpl(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.INCLUDE: + metadataTargetRegion.setIncluded(ReaderUtils.getBooleanJsonField(parser)); + break; + case StructureUtils.VALID_FROM: + metadataTargetRegion.setValidFrom(ReaderUtils.getInstantObj(parser)); + break; + case StructureUtils.VALID_TO: + metadataTargetRegion.setValidTo(ReaderUtils.getInstantObj(parser)); + break; + case StructureUtils.COMPONENTS: + List memberSelections = ReaderUtils.getArray(parser, (this::getMemberSelection)); + if (CollectionUtils.isNotEmpty(memberSelections)) { + metadataTargetRegion.setMemberSelections(memberSelections); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "MetadataTargetRegion: " + fieldName); + } + } + return metadataTargetRegion; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private MemberSelection getMemberSelection(JsonParser parser) { + return memberSelectionReader.getMemberSelection(parser); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataFlowReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataFlowReader.java new file mode 100644 index 0000000..7b82a8b --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataFlowReader.java @@ -0,0 +1,70 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableObjectSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.MetadataflowImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.apache.commons.collections.CollectionUtils; + +public class MetadataFlowReader extends MaintainableReader { + + public MetadataFlowReader(VersionableReader versionableArtefact) { + super(versionableArtefact); + } + + @Override + protected MetadataflowImpl createMaintainableArtefact() { + return new MetadataflowImpl(); + } + + @Override + public void readArtefact(JsonParser parser, MetadataflowImpl dataflow) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.STRUCTURE: + String urn = ReaderUtils.getStringJsonField(parser); + if (urn != null) { + dataflow.setStructure(new MaintainableArtefactReference(urn)); + } + break; + case StructureUtils.TARGETS: + List artefactRefs = ReaderUtils.getListStrings(parser); + if (CollectionUtils.isNotEmpty(artefactRefs)) { + List maintainableArtefactReferences = stringsToArtefactReferences(artefactRefs); + IdentifiableObjectSelectionImpl identifiableObjectSelection = new IdentifiableObjectSelectionImpl(); + identifiableObjectSelection.setResolvesTo(maintainableArtefactReferences); + dataflow.setSelections(List.of(identifiableObjectSelection)); + } + break; + default: + throw new IllegalStateException(StructureUtils.NO_SUCH_PROPERTY_IN + "Metadataflow: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.METADATAFLOWS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getMetadataflows().addAll(artefacts); + } + + private List stringsToArtefactReferences(List artefectRefs) { + return artefectRefs.stream() + .filter(Objects::nonNull) + .map(MaintainableArtefactReference::new) + .collect(Collectors.toList()); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataProviderSchemeReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataProviderSchemeReader.java new file mode 100644 index 0000000..b8729c9 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataProviderSchemeReader.java @@ -0,0 +1,64 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getBooleanJsonField; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProvider; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderSchemeImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.apache.commons.collections.CollectionUtils; + +public class MetadataProviderSchemeReader extends MaintainableReader { + + private final OrganisationReader organisationReader; + + public MetadataProviderSchemeReader(VersionableReader versionableArtefact, + OrganisationReader organisationReader) { + super(versionableArtefact); + this.organisationReader = organisationReader; + } + + @Override + protected MetadataProviderSchemeImpl createMaintainableArtefact() { + return new MetadataProviderSchemeImpl(); + } + + @Override + public void readArtefact(JsonParser parser, MetadataProviderSchemeImpl metadataProviderScheme) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.IS_PARTIAL: + metadataProviderScheme.setPartial(getBooleanJsonField(parser)); + break; + case StructureUtils.METADATA_PROVIDERS: + List dataProviders = ReaderUtils.getArray(parser, (this::getMetadataProvider)); + if (CollectionUtils.isNotEmpty(dataProviders)) { + metadataProviderScheme.setItems(dataProviders); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "MetadataProviderScheme: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.METADATA_PROVIDER_SCHEMES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getMetadataProviderSchemes().addAll(artefacts); + } + + private MetadataProvider getMetadataProvider(JsonParser parser) { + return organisationReader.getOrganisation(parser, new MetadataProviderImpl(), null); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataProvisionAgreementReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataProvisionAgreementReader.java new file mode 100644 index 0000000..68d1512 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/MetadataProvisionAgreementReader.java @@ -0,0 +1,55 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProvisionAgreementImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; + +public class MetadataProvisionAgreementReader extends MaintainableReader { + + public MetadataProvisionAgreementReader(VersionableReader versionableArtefact) { + super(versionableArtefact); + } + + @Override + protected MetadataProvisionAgreementImpl createMaintainableArtefact() { + return new MetadataProvisionAgreementImpl(); + } + + @Override + public void readArtefact(JsonParser parser, MetadataProvisionAgreementImpl provisionAgreement) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.METADATA_FLOW: + String dataflow = ReaderUtils.getStringJsonField(parser); + if (dataflow != null) { + provisionAgreement.setControlledStructureUsage(new MaintainableArtefactReference(dataflow)); + } + break; + case StructureUtils.METADATA_PROVIDER: + String dataProvider = ReaderUtils.getStringJsonField(parser); + if (dataProvider != null) { + provisionAgreement.setMetadataProvider(new IdentifiableArtefactReferenceImpl(dataProvider)); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "MetadataProvisionAgreement: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.METADATA_PROVISION_AGREEMENTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getMetadataProvisionAgreements().addAll(artefacts); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/NameableReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/NameableReader.java new file mode 100644 index 0000000..0594ab0 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/NameableReader.java @@ -0,0 +1,48 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.Map; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.NameableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.NameableArtefactImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; + +public class NameableReader { + + private final IdentifiableReader identifiableReader; + + public NameableReader(IdentifiableReader identifiableReader) { + this.identifiableReader = identifiableReader; + } + + public NameableArtefact read(NameableArtefactImpl maintainableArtefact, JsonParser parser) throws IOException { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.NAMES: + Map localizedNames = ReaderUtils.getLocalizedField(parser); + if (localizedNames != null) { + maintainableArtefact.setName(new InternationalString(localizedNames)); + } + break; + case StructureUtils.DESCRIPTIONS: + Map localizedDescriptions = ReaderUtils.getLocalizedField(parser); + if (localizedDescriptions != null) { + maintainableArtefact.setDescription(new InternationalString(localizedDescriptions)); + } + break; + case StructureUtils.DESCRIPTION: + case StructureUtils.NAME: + parser.nextToken(); + parser.skipChildren(); + break; + default: + identifiableReader.read(maintainableArtefact, parser); + break; + } + return maintainableArtefact; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/OrganisationReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/OrganisationReader.java new file mode 100644 index 0000000..5a2c505 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/OrganisationReader.java @@ -0,0 +1,83 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.Contact; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactImpl; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + +public class OrganisationReader { + + private final ContactReader contactReader; + private final NameableReader nameableReader; + + public OrganisationReader(ContactReader contactReader, + NameableReader nameableReader) { + this.contactReader = contactReader; + this.nameableReader = nameableReader; + } + + public > T getOrganisation(JsonParser parser, + T organisation, + Map organisationWithParentId) { + try { + String parentId = null; + while (parser.nextToken() != JsonToken.END_OBJECT) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.CONTACTS: + parser.nextToken(); + organisation.setContacts(ReaderUtils.getArray(parser, (this::getContact))); + break; + case StructureUtils.PARENT: + parentId = ReaderUtils.getStringJsonField(parser); + break; + default: + nameableReader.read(organisation, parser); + } + } + if (organisationWithParentId != null) { + organisationWithParentId.put(organisation, parentId); + } + return organisation; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + public > Map> formHierarchy(Map dataConsumerWithParent) { + Map> parentChildren = new HashMap<>(); + Set consumers = dataConsumerWithParent.keySet(); + Map consumerWithId = consumers.stream() + .collect(Collectors.toMap( + IdentifiableArtefactImpl::getId, + consumer -> consumer + )); + for (Map.Entry data : dataConsumerWithParent.entrySet()) { + String value = data.getValue(); + if (value != null) { + T dataConsumer = consumerWithId.get(value); + if (parentChildren.containsKey(dataConsumer)) { + parentChildren.get(dataConsumer).add(data.getKey()); + } else { + parentChildren.put(dataConsumer, List.of(data.getKey())); + } + } + } + return parentChildren; + } + + private Contact getContact(JsonParser parser) { + return contactReader.getContact(parser); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/OrganisationSchemeMapReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/OrganisationSchemeMapReader.java new file mode 100644 index 0000000..420564b --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/OrganisationSchemeMapReader.java @@ -0,0 +1,56 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationSchemeMapImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.apache.commons.collections.CollectionUtils; + +public class OrganisationSchemeMapReader extends MaintainableReader implements ItemMapReader { + + public OrganisationSchemeMapReader(VersionableReader versionableArtefact) { + super(versionableArtefact); + } + + @Override + protected OrganisationSchemeMapImpl createMaintainableArtefact() { + return new OrganisationSchemeMapImpl(); + } + + @Override + public void readArtefact(JsonParser parser, OrganisationSchemeMapImpl organisationSchemeMap) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.TARGET: + getTargetSource(parser).ifPresent(organisationSchemeMap::setTarget); + break; + case StructureUtils.SOURCE: + getTargetSource(parser).ifPresent(organisationSchemeMap::setSource); + break; + case StructureUtils.ITEM_MAPS: + List itemMaps = ReaderUtils.getArray(parser, (this::getItemMap)); + if (CollectionUtils.isNotEmpty(itemMaps)) { + organisationSchemeMap.setItemMaps(itemMaps); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "OrganisationSchemeMap: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.ORGANISATION_SCHEME_MAPS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getOrganisationSchemeMaps().addAll(artefacts); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/OrganisationUnitSchemeReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/OrganisationUnitSchemeReader.java new file mode 100644 index 0000000..359a691 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/OrganisationUnitSchemeReader.java @@ -0,0 +1,79 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getBooleanJsonField; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnit; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitImpl; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitSchemeImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.apache.commons.collections.CollectionUtils; + +public class OrganisationUnitSchemeReader extends MaintainableReader { + + private final OrganisationReader organisationReader; + private final Map organisationUnitStringMap = new HashMap<>(); + + public OrganisationUnitSchemeReader(VersionableReader versionableArtefact, + OrganisationReader organisationReader) { + super(versionableArtefact); + this.organisationReader = organisationReader; + } + + @Override + protected OrganisationUnitSchemeImpl createMaintainableArtefact() { + return new OrganisationUnitSchemeImpl(); + } + + @Override + public void readArtefact(JsonParser parser, OrganisationUnitSchemeImpl organisationUnitScheme) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.IS_PARTIAL: + organisationUnitScheme.setPartial(getBooleanJsonField(parser)); + break; + case StructureUtils.ORGANISATION_UNITS: + List organisationUnits = ReaderUtils.getArray(parser, (this::getOrganisationUnit)); + if (CollectionUtils.isNotEmpty(organisationUnits)) { + Map> organisationListMap = organisationReader.formHierarchy(organisationUnitStringMap); + for (Map.Entry> organisationHier : organisationListMap.entrySet()) { + List organisationUnitImplList = organisationHier.getValue(); + List organisationUnitList = new ArrayList<>(organisationUnitImplList); + organisationHier.getKey().setHierarchy(organisationUnitList); + } + organisationUnitScheme.setItems(organisationUnits); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "OrganisationUnitScheme: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.ORGANISATION_UNIT_SCHEMES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getOrganisationUnitSchemes().addAll(artefacts); + } + + private OrganisationUnit getOrganisationUnit(JsonParser parser) { + return organisationReader.getOrganisation(parser, new OrganisationUnitImpl(), organisationUnitStringMap); + } + + @Override + protected void clean() { + organisationUnitStringMap.clear(); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ProcessReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ProcessReader.java new file mode 100644 index 0000000..a6fe763 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ProcessReader.java @@ -0,0 +1,260 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getLocalizedField; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getStringJsonField; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Computation; +import com.epam.jsdmx.infomodel.sdmx30.ComputationImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.ProcessArtefact; +import com.epam.jsdmx.infomodel.sdmx30.ProcessArtefactImpl; +import com.epam.jsdmx.infomodel.sdmx30.ProcessImpl; +import com.epam.jsdmx.infomodel.sdmx30.ProcessStep; +import com.epam.jsdmx.infomodel.sdmx30.ProcessStepImpl; +import com.epam.jsdmx.infomodel.sdmx30.Transition; +import com.epam.jsdmx.infomodel.sdmx30.TransitionImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class ProcessReader extends MaintainableReader { + + private final NameableReader nameableReader; + private final AnnotableReader annotableReader; + private final IdentifiableReader identifiableReader; + + public ProcessReader(VersionableReader versionableArtefact, + NameableReader nameableReader, + AnnotableReader annotableReader, + IdentifiableReader identifiableReader) { + super(versionableArtefact); + this.nameableReader = nameableReader; + this.annotableReader = annotableReader; + this.identifiableReader = identifiableReader; + } + + @Override + protected ProcessImpl createMaintainableArtefact() { + return new ProcessImpl(); + } + + @Override + public void readArtefact(JsonParser parser, ProcessImpl process) throws IOException { + String fieldName = parser.getCurrentName(); + if (StructureUtils.PROCESS_STEPS.equals(fieldName)) { + List processSteps = ReaderUtils.getArray(parser, (this::getProcessStep)); + if (CollectionUtils.isNotEmpty(processSteps)) { + process.setSteps(processSteps); + } + } else { + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "Process: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.PROCESSES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getProcesses().addAll(artefacts); + } + + private ProcessStep getProcessStep(JsonParser parser) { + ProcessStepImpl processStep = new ProcessStepImpl(); + try { + while (parser.nextToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.COMPUTATION: + processStep.setComputation(getComputation(parser)); + break; + case StructureUtils.TRANSITIONS: + setTransitions(parser, processStep); + break; + case StructureUtils.OUTPUTS: + List outputs = ReaderUtils.getArray(parser, (this::getInputOutput)); + if (CollectionUtils.isNotEmpty(outputs)) { + processStep.setOutputs(outputs); + } + break; + case StructureUtils.INPUTS: + List inputs = ReaderUtils.getArray(parser, (this::getInputOutput)); + if (CollectionUtils.isNotEmpty(inputs)) { + processStep.setInputs(inputs); + } + break; + case StructureUtils.PROCESS_STEPS: + List processSteps = ReaderUtils.getArray(parser, (this::getProcessStep)); + if (CollectionUtils.isNotEmpty(processSteps)) { + processStep.setChildren(processSteps); + } + break; + default: + nameableReader.read(processStep, parser); + break; + } + } + return processStep; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private void setTransitions(JsonParser parser, ProcessStepImpl processStep) throws IOException { + List transitions = ReaderUtils.getArray(parser, (this::getTransitions)); + if (CollectionUtils.isNotEmpty(transitions)) { + processStep.setTransitions(transitions); + } + } + + private Transition getTransitions(JsonParser parser) { + TransitionImpl transition = new TransitionImpl(); + try { + while (parser.nextToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.LOCAL_ID: + String localID = getStringJsonField(parser); + if (localID != null) { + transition.setLocalId(localID); + } + break; + case StructureUtils.CONDITION: + parser.nextToken(); + parser.skipChildren(); + break; + case StructureUtils.CONDITIONS: + Map conditions = getLocalizedField(parser); + if (conditions != null) { + transition.setCondition(new InternationalString(conditions)); + } + break; + case StructureUtils.TARGET_STEP: + String targetStep = getStringJsonField(parser); + if (targetStep != null) { + transition.setTargetProcessStep(targetStep); + } + break; + default: + identifiableReader.read(transition, parser); + break; + } + } + return transition; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private ProcessArtefact getInputOutput(JsonParser parser) { + ProcessArtefactImpl processArtefact = new ProcessArtefactImpl(); + try { + while (parser.nextToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.LOCAL_ID: + String localID = getStringJsonField(parser); + if (localID != null) { + processArtefact.setLocalId(localID); + } + break; + case StructureUtils.OBJECT_REFERENCE: + String objectRef = getStringJsonField(parser); + if (objectRef != null) { + processArtefact.setArtefact(new MaintainableArtefactReference(objectRef)); + } + break; + default: + annotableReader.read(processArtefact, parser); + break; + } + } + return processArtefact; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private Computation getComputation(JsonParser parser) throws IOException { + ComputationImpl computation = new ComputationImpl(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.LOCAL_ID: + setLocalId(parser, computation); + break; + case StructureUtils.SOFTWARE_LANGUAGE: + setSoftwareLanguage(parser, computation); + break; + case StructureUtils.SOFTWARE_PACKAGE: + setSoftwarePackage(parser, computation); + break; + case StructureUtils.SOFTWARE_VERSION: + setSoftwareVersion(parser, computation); + break; + case StructureUtils.DESCRIPTION: + parser.nextToken(); + parser.skipChildren(); + break; + case StructureUtils.DESCRIPTIONS: + setDescription(parser, computation); + break; + default: + annotableReader.read(computation, parser); + break; + } + } + return computation; + } + + private void setSoftwareLanguage(JsonParser parser, ComputationImpl computation) throws IOException { + String softwareLanguage = getStringJsonField(parser); + if (softwareLanguage != null) { + computation.setSoftwareLanguage(softwareLanguage); + } + } + + private void setSoftwarePackage(JsonParser parser, ComputationImpl computation) throws IOException { + String softwarePackage = getStringJsonField(parser); + if (softwarePackage != null) { + computation.setSoftwarePackage(softwarePackage); + } + } + + private void setSoftwareVersion(JsonParser parser, ComputationImpl computation) throws IOException { + String softwareVersion = getStringJsonField(parser); + if (softwareVersion != null) { + computation.setSoftwareVersion(softwareVersion); + } + } + + private void setDescription(JsonParser parser, ComputationImpl computation) throws IOException { + Map localizedDescriptions = getLocalizedField(parser); + if (localizedDescriptions != null) { + computation.setDescription(new InternationalString(localizedDescriptions)); + } + } + + private void setLocalId(JsonParser parser, ComputationImpl computation) throws IOException { + String localID = getStringJsonField(parser); + if (localID != null) { + computation.setLocalId(localID); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ProvisionAgreementReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ProvisionAgreementReader.java new file mode 100644 index 0000000..d7db4cf --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ProvisionAgreementReader.java @@ -0,0 +1,55 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.ProvisionAgreementImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; + +public class ProvisionAgreementReader extends MaintainableReader { + + public ProvisionAgreementReader(VersionableReader versionableArtefact) { + super(versionableArtefact); + } + + @Override + protected ProvisionAgreementImpl createMaintainableArtefact() { + return new ProvisionAgreementImpl(); + } + + @Override + public void readArtefact(JsonParser parser, ProvisionAgreementImpl provisionAgreement) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.DATAFLOW: + String dataflow = ReaderUtils.getStringJsonField(parser); + if (dataflow != null) { + provisionAgreement.setControlledStructureUsage(new MaintainableArtefactReference(dataflow)); + } + break; + case StructureUtils.DATA_PROVIDER: + String dataProvider = ReaderUtils.getStringJsonField(parser); + if (dataProvider != null) { + provisionAgreement.setDataProvider(new IdentifiableArtefactReferenceImpl(dataProvider)); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "ProvisionAgreement: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.PROVISION_AGREEMENTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getProvisionAgreements().addAll(artefacts); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReaderUtils.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReaderUtils.java new file mode 100644 index 0000000..1f789f0 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReaderUtils.java @@ -0,0 +1,191 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.ChronoField; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import com.epam.jsdmx.infomodel.sdmx30.Annotation; +import com.epam.jsdmx.infomodel.sdmx30.AnnotationImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ReaderUtils { + + public static Map getLocalizedField(JsonParser parser) throws IOException { + return getLocalizedField(parser, false); + } + + public static Map getLocalizedField(JsonParser parser, boolean skipFirstToken) throws IOException { + Map localisations = new HashMap<>(); + if (!skipFirstToken) { + parser.nextToken(); + } + while (!JsonToken.END_OBJECT.equals(parser.getCurrentToken())) { + if (!checkIsNotEmptyObjectAndSkipUntilFieldName(parser)) { + return null; + } + String locale = parser.getCurrentName(); + parser.nextToken(); + String text = parser.getText(); + localisations.put(locale, text); + parser.nextToken(); + } + return localisations; + } + + public static List getArray(JsonParser parser, Function function) throws IOException { + List listObj = new ArrayList<>(); + while (!JsonToken.END_ARRAY.equals(parser.nextToken()) && parser.hasCurrentToken()) { + if (JsonToken.START_OBJECT.equals(parser.currentToken())) { + listObj.add(function.apply(parser)); + } + } + return listObj; + } + + public static List getListStrings(JsonParser parser) throws IOException { + List strings = new ArrayList<>(); + parser.nextToken(); + while (parser.currentToken() != JsonToken.END_ARRAY) { + if (parser.currentToken().equals(JsonToken.START_ARRAY) + && parser.nextToken().equals(JsonToken.END_ARRAY)) { + return strings; + } + String text = parser.getText(); + if (text != null) { + strings.add(text); + } + parser.nextToken(); + } + return strings; + } + + public static String getStringJsonField(JsonParser parser) throws IOException { + parser.nextToken(); + if (JsonToken.VALUE_NULL.equals(parser.getCurrentToken())) { + return null; + } + return parser.getText(); + } + + public static String getFieldAsString(JsonParser parser) throws IOException { + parser.nextToken(); + if (JsonToken.VALUE_NULL.equals(parser.getCurrentToken())) { + return null; + } + return parser.getValueAsString(); + } + + public static boolean getBooleanJsonField(JsonParser parser) throws IOException { + parser.nextToken(); + if (JsonToken.VALUE_NULL.equals(parser.getCurrentToken())) { + throw new IllegalArgumentException("value can't be null"); + } + return parser.getBooleanValue(); + } + + public static int getIntJsonField(JsonParser parser) throws IOException { + parser.nextToken(); + if (JsonToken.VALUE_NULL.equals(parser.getCurrentToken())) { + throw new IllegalArgumentException("value can't be null"); + } + return parser.getIntValue(); + } + + public static boolean checkIsNotEmptyObjectAndSkipUntilFieldName(JsonParser parser) throws IOException { + while (!JsonToken.FIELD_NAME.equals(parser.currentToken())) { + if (JsonToken.END_OBJECT.equals(parser.getCurrentToken())) { + // skip empty object + return false; + } + if (parser.currentToken() == null) { + return false; + } + parser.nextToken(); + } + return true; + } + + public static boolean isNullValue(JsonParser parser) { + return JsonToken.VALUE_NULL.equals(parser.currentToken()); + } + + public static Instant getInstantObj(JsonParser parser) throws IOException { + parser.nextToken(); + if (JsonToken.VALUE_NULL.equals(parser.getCurrentToken())) { + return null; + } + String data = parser.getText(); + return mapStringToInstant(data); + } + + public static Instant mapStringToInstant(String time) { + if (time.contains(StructureUtils.ZONE)) { + return Instant.from(getDateTimeFormatterWithZone().parse(time)); + } else { + LocalDateTime localDateTime = LocalDateTime.parse(time, getDateTimeFormatterWithoutZone()); + return localDateTime.atZone(ZoneOffset.UTC).toInstant(); + } + } + + + private static DateTimeFormatter getDateTimeFormatterWithoutZone() { + return new DateTimeFormatterBuilder() + .appendPattern(StructureUtils.BASIC_TIME_FORMAT) + .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 9, true) + .toFormatter(); + } + + private static DateTimeFormatter getDateTimeFormatterWithZone() { + return new DateTimeFormatterBuilder() + .appendPattern(StructureUtils.BASIC_TIME_FORMAT) + .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 9, true) + .appendZoneOrOffsetId() + .toFormatter(); + } + + public static List readJsonStringAnnotations(String annotations, String artefactId) { + if (StringUtils.isNotBlank(annotations)) { + try { + ObjectMapper objectMapper = new ObjectMapper(); + JsonParser parser = objectMapper.getFactory().createParser(annotations); + + parser.nextToken(); + + List annotationList = new ArrayList<>(); + AnnotableReader annotableReader = new AnnotableReader(); + + while (parser.currentToken() != JsonToken.END_ARRAY) { + if (parser.currentToken() == JsonToken.START_OBJECT) { + AnnotationImpl annotation = annotableReader.readAnnotation(parser); + annotationList.add(annotation); + } else { + parser.nextToken(); + } + } + + return annotationList; + } catch (Exception e) { + throw new JsonRuntimeException("Problem during parsing annotation form JSON for: " + artefactId); + } + } else { + return new ArrayList<>(); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReleaseCalendarReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReleaseCalendarReader.java new file mode 100644 index 0000000..faf20de --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReleaseCalendarReader.java @@ -0,0 +1,35 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendar; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendarImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + +public class ReleaseCalendarReader { + + public ReleaseCalendar getReleaseCalendar(JsonParser parser) throws IOException { + ReleaseCalendarImpl releaseCalendar = new ReleaseCalendarImpl(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.OFFSET: + releaseCalendar.setOffset(ReaderUtils.getFieldAsString(parser)); + break; + case StructureUtils.TOLERANCE: + releaseCalendar.setTolerance(ReaderUtils.getFieldAsString(parser)); + break; + case StructureUtils.PERIODICITY: + releaseCalendar.setPeriodicity(ReaderUtils.getFieldAsString(parser)); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + " ReleaseCalendar: " + fieldName); + } + } + return releaseCalendar; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReportingTaxonomyMapReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReportingTaxonomyMapReader.java new file mode 100644 index 0000000..8bcaac9 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReportingTaxonomyMapReader.java @@ -0,0 +1,56 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyMapImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.apache.commons.collections.CollectionUtils; + +public class ReportingTaxonomyMapReader extends MaintainableReader implements ItemMapReader { + + public ReportingTaxonomyMapReader(VersionableReader versionableArtefact) { + super(versionableArtefact); + } + + @Override + protected ReportingTaxonomyMapImpl createMaintainableArtefact() { + return new ReportingTaxonomyMapImpl(); + } + + @Override + public void readArtefact(JsonParser parser, ReportingTaxonomyMapImpl reportingTaxonomyMap) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.TARGET: + getTargetSource(parser).ifPresent(reportingTaxonomyMap::setTarget); + break; + case StructureUtils.SOURCE: + getTargetSource(parser).ifPresent(reportingTaxonomyMap::setSource); + break; + case StructureUtils.ITEM_MAPS: + List itemMaps = ReaderUtils.getArray(parser, (this::getItemMap)); + if (CollectionUtils.isNotEmpty(itemMaps)) { + reportingTaxonomyMap.setItemMaps(itemMaps); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "ReportingTaxonomyMap: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.REPORTING_TAXONOMY_MAPS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getReportingTaxonomyMaps().addAll(artefacts); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReportingTaxonomyReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReportingTaxonomyReader.java new file mode 100644 index 0000000..de2afc3 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ReportingTaxonomyReader.java @@ -0,0 +1,99 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.ReportingCategory; +import com.epam.jsdmx.infomodel.sdmx30.ReportingCategoryImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class ReportingTaxonomyReader extends MaintainableReader { + + private final NameableReader nameableReader; + + public ReportingTaxonomyReader(VersionableReader versionableArtefact, + NameableReader nameableReader) { + super(versionableArtefact); + this.nameableReader = nameableReader; + } + + @Override + protected ReportingTaxonomyImpl createMaintainableArtefact() { + return new ReportingTaxonomyImpl(); + } + + @Override + public void readArtefact(JsonParser parser, ReportingTaxonomyImpl reportingTaxonomy) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.IS_PARTIAL: + reportingTaxonomy.setPartial(ReaderUtils.getBooleanJsonField(parser)); + break; + case StructureUtils.REPORTING_CATEGORIES: + List reportingCategories = ReaderUtils.getArray(parser, (this::getReportingCategory)); + if (CollectionUtils.isNotEmpty(reportingCategories)) { + reportingTaxonomy.setItems(reportingCategories); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "ReportingTaxonomy: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.REPORTING_TAXONOMIES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getReportingTaxonomies().addAll(artefacts); + } + + private ReportingCategory getReportingCategory(JsonParser parser) { + ReportingCategoryImpl reportingCategory = new ReportingCategoryImpl(); + try { + while (parser.nextToken() != JsonToken.END_OBJECT) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.REPORTING_CATEGORIES: + parser.nextToken(); + reportingCategory.setHierarchy(ReaderUtils.getArray(parser, (this::getReportingCategory))); + break; + case StructureUtils.STRUCTURAL_METADATA: + List structureReferenceUris = ReaderUtils.getListStrings(parser); + List structureRef = structureReferenceUris.stream().filter(Objects::nonNull) + .map(MaintainableArtefactReference::new) + .collect(Collectors.toList()); + reportingCategory.setStructures(structureRef); + break; + case StructureUtils.PROVISIONING_METADATA: + List provisioningReferenceUris = ReaderUtils.getListStrings(parser); + List provisionRef = provisioningReferenceUris.stream().filter(Objects::nonNull) + .map(MaintainableArtefactReference::new) + .collect(Collectors.toList()); + reportingCategory.setFlows(provisionRef); + break; + default: + nameableReader.read(reportingCategory, parser); + break; + } + } + return reportingCategory; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } +} \ No newline at end of file diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/RepresentationMapReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/RepresentationMapReader.java new file mode 100644 index 0000000..69f8854 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/RepresentationMapReader.java @@ -0,0 +1,230 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getInstantObj; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueTypeRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.ListReferenceValueRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.MappedValue; +import com.epam.jsdmx.infomodel.sdmx30.MappedValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapping; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMappingImpl; +import com.epam.jsdmx.infomodel.sdmx30.TargetValue; +import com.epam.jsdmx.infomodel.sdmx30.TargetValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.ValueRepresentation; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class RepresentationMapReader extends MaintainableReader { + + public RepresentationMapReader(VersionableReader versionableArtefact) { + super(versionableArtefact); + } + + @Override + protected RepresentationMapImpl createMaintainableArtefact() { + return new RepresentationMapImpl(); + } + + @Override + public void readArtefact(JsonParser parser, RepresentationMapImpl representationMap) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.SOURCE: + List valueRepresentationSource = getValueRepresentation(parser); + if (CollectionUtils.isNotEmpty(valueRepresentationSource)) { + representationMap.setSource(valueRepresentationSource); + } + break; + case StructureUtils.TARGET: + List valueRepresentationTarget = getValueRepresentation(parser); + if (CollectionUtils.isNotEmpty(valueRepresentationTarget)) { + representationMap.setTarget(valueRepresentationTarget); + } + break; + case StructureUtils.REPRESENTATION_MAPPINGS: + List representationMappings = getRepresentationMappings(parser); + if (CollectionUtils.isNotEmpty(representationMappings)) { + representationMap.setRepresentationMappings(representationMappings); + } + break; + default: + throw new IllegalArgumentException("no such argument in RepresentationMap: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.REPRESENTATION_MAPS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getRepresentationMaps().addAll(artefacts); + } + + private List getRepresentationMappings(JsonParser parser) throws IOException { + List representationMappings = new ArrayList<>(); + while (parser.nextToken() != JsonToken.END_ARRAY) { + if (parser.currentToken() + .equals(JsonToken.START_OBJECT)) { + RepresentationMapping representationMapping = getRepresentationMapping(parser); + representationMappings.add(representationMapping); + } + } + return representationMappings; + } + + private RepresentationMappingImpl getRepresentationMapping(JsonParser parser) throws IOException { + RepresentationMappingImpl representationMapping = new RepresentationMappingImpl(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.VALID_TO: + representationMapping.setValidTo(getInstantObj(parser)); + break; + case StructureUtils.VALID_FROM: + representationMapping.setValidFrom(getInstantObj(parser)); + break; + case StructureUtils.TARGET_VALUES: + List targetValues = getTargetValues(parser); + if (CollectionUtils.isNotEmpty(targetValues)) { + representationMapping.setTargetValues(targetValues); + } + break; + case StructureUtils.SOURCE_VALUES: + List sourceValues = getSourceValues(parser); + if (CollectionUtils.isNotEmpty(sourceValues)) { + representationMapping.setSourceValues(sourceValues); + } + break; + default: + AnnotableReader annotableReader = new AnnotableReader(); + annotableReader.read(representationMapping, parser); + break; + } + } + return representationMapping; + } + + private List getSourceValues(JsonParser parser) throws IOException { + List mappedValues = new ArrayList<>(); + while (parser.nextToken() != JsonToken.END_ARRAY) { + if (parser.currentToken() + .equals(JsonToken.START_OBJECT)) { + MappedValue mappedValue = getMappedValue(parser); + mappedValues.add(mappedValue); + } + } + return mappedValues; + } + + private MappedValue getMappedValue(JsonParser parser) throws IOException { + MappedValueImpl mappedValue = new MappedValueImpl(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.IS_REG_EX: + mappedValue.setRegEx(ReaderUtils.getBooleanJsonField(parser)); + break; + case StructureUtils.START_INDEX: + mappedValue.setStartIndex(ReaderUtils.getIntJsonField(parser)); + break; + case StructureUtils.END_INDEX: + mappedValue.setEndIndex(ReaderUtils.getIntJsonField(parser)); + break; + case StructureUtils.VALUE: + mappedValue.setValue(ReaderUtils.getStringJsonField(parser)); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "MappedValue:" + fieldName); + } + } + return mappedValue; + } + + private List getTargetValues(JsonParser parser) throws IOException { + List stringList = ReaderUtils.getListStrings(parser); + return stringList.stream() + .filter(Objects::nonNull) + .map(str -> { + TargetValueImpl targetValue = new TargetValueImpl(); + targetValue.setValue(str); + return targetValue; + }) + .collect(Collectors.toList()); + } + + private List getValueRepresentation(JsonParser parser) throws IOException { + List valueRepresentations = new ArrayList<>(); + while (parser.nextToken() != JsonToken.END_ARRAY) { + if (parser.currentToken() + .equals(JsonToken.START_OBJECT)) { + setValueRepresentation(parser, valueRepresentations); + } + } + return valueRepresentations; + } + + private void setValueRepresentation(JsonParser parser, List valueRepresentations) throws IOException { + boolean isCodeList = false; + boolean isDataType = false; + while (parser.nextToken() != JsonToken.END_OBJECT) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.CODE_LIST: + isCodeList = true; + valueRepresentations.add(readCodeList(parser, isDataType)); + break; + case StructureUtils.DATA_TYPE: + isDataType = true; + valueRepresentations.add(readDataType(parser, isCodeList)); + break; + default: + throw new IllegalArgumentException("ElementDto must contain codelist or dataType"); + } + } + } + + private ValueRepresentation readDataType(JsonParser parser, boolean isSecondRepresentation) throws IOException { + if (isSecondRepresentation) { + throw new IllegalArgumentException("ElementDto should not contain both codelist and dataType at the same time"); + } + String dataType = ReaderUtils.getStringJsonField(parser); + if (dataType != null) { + FacetValueTypeRepresentationImpl facetValueRepresentation = new FacetValueTypeRepresentationImpl(); + facetValueRepresentation.setType(FacetValueType.fromValue(dataType)); + return facetValueRepresentation; + } + return null; + } + + private ValueRepresentation readCodeList(JsonParser parser, boolean isDataType) throws IOException { + if (isDataType) { + throw new IllegalArgumentException("ElementDto should not contain both codelist and dataType at the same time"); + } + String urn = ReaderUtils.getStringJsonField(parser); + if (urn != null) { + ListReferenceValueRepresentationImpl listValueRepresentation = new ListReferenceValueRepresentationImpl(); + listValueRepresentation.setReference(new MaintainableArtefactReference(urn)); + return listValueRepresentation; + } + return null; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/RepresentationReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/RepresentationReader.java new file mode 100644 index 0000000..80ca33c --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/RepresentationReader.java @@ -0,0 +1,196 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getLocalizedField; +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getStringJsonField; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.BaseFacetImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseTextFormatRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.EnumeratedRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.Facet; +import com.epam.jsdmx.infomodel.sdmx30.FacetType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.infomodel.sdmx30.SentinelValue; +import com.epam.jsdmx.infomodel.sdmx30.SentinelValueImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import lombok.NoArgsConstructor; +import org.apache.commons.collections.CollectionUtils; + +@NoArgsConstructor +public class RepresentationReader { + + public Representation getRepresentations(JsonParser parser) throws IOException { + parser.nextToken(); + if (ReaderUtils.isNullValue(parser)) { + return null; + } + if (parser.currentToken() + .equals(JsonToken.START_OBJECT) && parser.nextToken() + .equals(JsonToken.END_OBJECT)) { + return null; + } + String enumeration = null; + while (!JsonToken.END_OBJECT.equals(parser.currentToken())) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.ENUMERATION: + enumeration = ReaderUtils.getFieldAsString(parser); + if (enumeration != null) { + parser.nextToken(); + return new EnumeratedRepresentationImpl(new MaintainableArtefactReference(enumeration)); + } + return null; + case StructureUtils.ENUMERATION_FORMAT: + parser.nextToken(); + parser.skipChildren(); + break; + case StructureUtils.FORMAT: + final Representation representation = readFormat(parser); + parser.nextToken(); + return representation; + case StructureUtils.MIN_OCCURS: + case StructureUtils.MAX_OCCURS: + parser.nextToken(); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "Representation: " + fieldName); + } + } + + return null; + } + + private Representation readFormat(JsonParser parser) throws IOException { + parser.nextToken(); + Set facets = new HashSet<>(); + List sentinelValues = new ArrayList<>(); + FacetValueType facetValueType = null; + while (parser.nextToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.currentName(); + switch (fieldName) { + case StructureUtils.DATA_TYPE: + parser.nextToken(); + String dataType = parser.getText(); + facetValueType = FacetValueType.fromValue(dataType); + facets.add(new BaseFacetImpl(facetValueType)); + break; + case StructureUtils.IS_SEQUENCE: + facets.add(setFacet(FacetType.IS_SEQUENCE, parser)); + break; + case StructureUtils.INTERVAL: + facets.add(setFacet(FacetType.INTERVAL, parser)); + break; + case StructureUtils.TIME_INTERVAL: + facets.add(setFacet(FacetType.TIME_INTERVAL, parser)); + break; + case StructureUtils.START_VALUE: + facets.add(setFacet(FacetType.START_VALUE, parser)); + break; + case StructureUtils.END_VALUE: + facets.add(setFacet(FacetType.END_VALUE, parser)); + break; + case StructureUtils.MIN_LENGTH: + facets.add(setFacet(FacetType.MIN_LENGTH, parser)); + break; + case StructureUtils.MAX_LENGTH: + facets.add(setFacet(FacetType.MAX_LENGTH, parser)); + break; + case StructureUtils.MIN_VALUE: + facets.add(setFacet(FacetType.MIN_VALUE, parser)); + break; + case StructureUtils.MAX_VALUE: + facets.add(setFacet(FacetType.MAX_VALUE, parser)); + break; + case StructureUtils.PATTERN: + facets.add(setFacet(FacetType.PATTERN, parser)); + break; + case StructureUtils.DECIMALS: + facets.add(setFacet(FacetType.DECIMALS, parser)); + break; + case StructureUtils.IS_MULTI_LINGUAL: + facets.add(setFacet(FacetType.IS_MULTILINGUAL, parser)); + break; + case StructureUtils.SENTINEL_VALUES: + List sentinelValueList = ReaderUtils.getArray(parser, (this::getSentinelValue)); + if (CollectionUtils.isNotEmpty(sentinelValueList)) { + sentinelValues.addAll(sentinelValueList); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + + "CodingFormat:" + fieldName); + } + } + if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(sentinelValues)) { + BaseFacetImpl baseFacet = new BaseFacetImpl(); + baseFacet.setType(FacetType.SENTINEL_VALUES); + baseFacet.setValueType(facetValueType); + baseFacet.setSentinelValues(sentinelValues); + facets.add(baseFacet); + } + + return new BaseTextFormatRepresentationImpl(facets); + } + + private SentinelValue getSentinelValue(JsonParser parser) { + try { + SentinelValueImpl sentinelValue = new SentinelValueImpl(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.currentName(); + switch (fieldName) { + case StructureUtils.VALUE: + String value = getStringJsonField(parser); + if (value != null) { + sentinelValue.setValue(value); + } + break; + case StructureUtils.NAMES: + Map localizedNames = getLocalizedField(parser); + if (localizedNames != null) { + sentinelValue.setName(new InternationalString(localizedNames)); + } + break; + case StructureUtils.DESCRIPTION: + case StructureUtils.NAME: + parser.nextToken(); + parser.skipChildren(); + break; + case StructureUtils.DESCRIPTIONS: + Map localizedDescriptions = getLocalizedField(parser); + if (localizedDescriptions != null) { + sentinelValue.setDescription(new InternationalString(localizedDescriptions)); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + " SentinelValue: " + fieldName); + } + } + return sentinelValue; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private Facet setFacet(FacetType type, JsonParser parser) throws IOException { + final var baseFacetStartValue = new BaseFacetImpl(); + baseFacetStartValue.setType(type); + baseFacetStartValue.setValue(ReaderUtils.getFieldAsString(parser)); + return baseFacetStartValue; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/StructureMapReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/StructureMapReader.java new file mode 100644 index 0000000..cc0d7d4 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/StructureMapReader.java @@ -0,0 +1,432 @@ +package com.epam.jsdmx.json20.structure.reader; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ComponentMap; +import com.epam.jsdmx.infomodel.sdmx30.ComponentMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.DateMap; +import com.epam.jsdmx.infomodel.sdmx30.DatePatternMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.EpochMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.EpochPeriodType; +import com.epam.jsdmx.infomodel.sdmx30.FixedValueMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.FrequencyFormatMapping; +import com.epam.jsdmx.infomodel.sdmx30.FrequencyFormatMappingImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.ResolvePeriod; +import com.epam.jsdmx.infomodel.sdmx30.StructureMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.YearStart; +import com.epam.jsdmx.json20.structure.writer.MappedComponent; +import com.epam.jsdmx.json20.structure.writer.StructureMapUtils; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import lombok.Getter; +import lombok.Setter; +import lombok.SneakyThrows; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.EnumUtils; + +@Getter +@Setter +public class StructureMapReader extends MaintainableReader { + + private AnnotableReader annotableReader; + private IdentifiableReader identifiableReader; + + private HashMap> datePatternFreqDimensionIds; + private HashMap> epochFreqDimensionIds; + private List frequencyIds = new ArrayList<>(); + private List frequencyFormatMappings; + private List componentMaps; + private HashMap mappedComponentsDP; + private HashMap mappedComponentsEpoch; + + public StructureMapReader(VersionableReader versionableReader, IdentifiableReader identifiableReader, AnnotableReader annotableReader) { + super(versionableReader); + this.identifiableReader = identifiableReader; + this.annotableReader = annotableReader; + this.datePatternFreqDimensionIds = new HashMap<>(); + this.epochFreqDimensionIds = new HashMap<>(); + this.mappedComponentsDP = new HashMap<>(); + this.mappedComponentsEpoch = new HashMap<>(); + this.frequencyFormatMappings = new ArrayList<>(); + this.componentMaps = new ArrayList<>(); + } + + @Override + protected void clean() { + this.datePatternFreqDimensionIds.clear(); + this.epochFreqDimensionIds.clear(); + this.mappedComponentsDP.clear(); + this.mappedComponentsEpoch.clear(); + this.frequencyFormatMappings.clear(); + this.componentMaps.clear(); + } + + @Override + protected StructureMapImpl createMaintainableArtefact() { + return new StructureMapImpl(); + } + + @Override + public StructureMapImpl read(JsonParser parser) throws IOException { + StructureMapImpl structureMap = super.read(parser); + + List freqIds = frequencyFormatMappings.stream() + .filter(Objects::nonNull) + .map(IdentifiableArtefact::getId) + .collect(Collectors.toList()); + + setDatePatternMapFrequencyDimensions(datePatternFreqDimensionIds, frequencyFormatMappings, freqIds); + setEpochMapFrequencyDimensions(epochFreqDimensionIds, frequencyFormatMappings, freqIds); + + List componentMapsDatePattern + = StructureMapUtils.extractComponentMapFromDatePatternMap(mappedComponentsDP, structureMap); + List componentMapsEpoch = StructureMapUtils.extractComponentMapFromEpochMap( + mappedComponentsEpoch, + structureMap + ); + + List allComponentMaps = Stream.of(componentMapsDatePattern, componentMapsEpoch, componentMaps) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + if (CollectionUtils.isNotEmpty(allComponentMaps)) { + structureMap.setComponentMaps(allComponentMaps); + } + + return structureMap; + } + + private void setDatePatternMapFrequencyDimensions(Map> datePatternFreqDimensionIds, + List frequencyFormatMappings, + List freqIds) { + for (Map.Entry> freqIdsFromDatePattern : datePatternFreqDimensionIds.entrySet()) { + List frequencyFormatMappingIds = freqIds.stream() + .filter(id -> freqIdsFromDatePattern.getValue().contains(id)) + .collect(Collectors.toList()); + + List formatMappings = frequencyFormatMappings.stream() + .filter(freq -> frequencyFormatMappingIds.contains(freq.getId())) + .collect(Collectors.toList()); + + freqIdsFromDatePattern.getKey() + .setMappedFrequencies(formatMappings); + } + } + + private void setEpochMapFrequencyDimensions(Map> epochMapFreqDimensionIds, + List frequencyFormatMappings, + List freqIds) { + for (Map.Entry> freqIdsFromEpochMap : epochMapFreqDimensionIds.entrySet()) { + List frequencyFormatMappingIds = freqIds.stream() + .filter(id -> freqIdsFromEpochMap.getValue().contains(id)) + .collect(Collectors.toList()); + + List formatMappings = frequencyFormatMappings.stream() + .filter(freq -> frequencyFormatMappingIds.contains(freq.getId())) + .collect(Collectors.toList()); + + freqIdsFromEpochMap.getKey() + .setMappedFrequencies(formatMappings); + } + } + + @Override + public void readArtefact(JsonParser parser, StructureMapImpl structureMap) throws IOException { + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.SOURCE: + String source = ReaderUtils.getStringJsonField(parser); + if (source != null) { + structureMap.setSource(new MaintainableArtefactReference(source)); + } + break; + case StructureUtils.TARGET: + String target = ReaderUtils.getStringJsonField(parser); + if (target != null) { + structureMap.setTarget(new MaintainableArtefactReference(target)); + } + break; + case StructureUtils.FREQUENCY_FORMAT_MAPPINGS: + frequencyFormatMappings = ReaderUtils.getArray(parser, this::getFrequenciesFormatMapping); + frequencyIds = frequencyFormatMappings.stream() + .filter(Objects::nonNull) + .map(IdentifiableArtefact::getId) + .collect(Collectors.toList()); + break; + case StructureUtils.DATE_PATTERN_MAPS: + List datePatternMaps = ReaderUtils.getArray(parser, this::getDatePatternMap); + if (CollectionUtils.isNotEmpty(datePatternMaps)) { + structureMap.setDatePatternMaps(new ArrayList<>(datePatternMaps)); + } + break; + case StructureUtils.FIXED_VALUE_MAPS: + List fixedValueMaps = ReaderUtils.getArray(parser, this::getFixedValueMap); + if (CollectionUtils.isNotEmpty(fixedValueMaps)) { + structureMap.setFixedComponentMaps(new ArrayList<>(fixedValueMaps)); + } + break; + case StructureUtils.EPOCH_MAPS: + List epochMaps = ReaderUtils.getArray(parser, this::getEpochMap); + if (CollectionUtils.isNotEmpty(epochMaps)) { + structureMap.setEpochMaps(new ArrayList<>(epochMaps)); + } + break; + case StructureUtils.COMPONENT_MAPS: + List componentMapList = ReaderUtils.getArray(parser, this::getComponentMap); + if (CollectionUtils.isNotEmpty(componentMapList)) { + this.componentMaps.addAll(componentMapList); + } + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "StructureMap: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.STRUCTURE_MAP; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getStructureMaps().addAll(artefacts); + } + + private ComponentMapImpl getComponentMap(JsonParser parser) { + try { + ComponentMapImpl componentMap = new ComponentMapImpl(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.SOURCE: + List sorces = ReaderUtils.getListStrings(parser); + componentMap.setSource(sorces); + break; + case StructureUtils.TARGET: + List targets = ReaderUtils.getListStrings(parser); + componentMap.setTarget(targets); + break; + case StructureUtils.REPRESENTATION_MAP: + String representationMap = ReaderUtils.getStringJsonField(parser); + componentMap.setRepresentationMap(new IdentifiableArtefactReferenceImpl(representationMap)); + break; + default: + annotableReader.read(componentMap, parser); + break; + } + } + return componentMap; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private FrequencyFormatMappingImpl getFrequenciesFormatMapping(JsonParser parser) { + try { + FrequencyFormatMappingImpl frequencyFormatMapping = new FrequencyFormatMappingImpl(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.FREQUENCY_ID: + frequencyFormatMapping.setFrequencyCode(ReaderUtils.getStringJsonField(parser)); + break; + case StructureUtils.DATE_PATTERN: + frequencyFormatMapping.setDatePattern(ReaderUtils.getStringJsonField(parser)); + break; + default: + identifiableReader.read(frequencyFormatMapping, parser); + break; + } + } + return frequencyFormatMapping; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + private DatePatternMapImpl getDatePatternMap(JsonParser parser) { + try { + DatePatternMapImpl datePatternMap = new DatePatternMapImpl(); + List datePatternMapFreqIds = new ArrayList<>(); + List datePatternMappedComponents = new ArrayList<>(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.RESOLVE_PERIOD: + String resolvePeriod = ReaderUtils.getStringJsonField(parser); + if (resolvePeriod != null) { + datePatternMap.setResolvePeriod(ResolvePeriod.valueOf(resolvePeriod)); + } + break; + case StructureUtils.YEAR_START: + Optional yearStart = getYearStart(parser); + yearStart.ifPresent(datePatternMap::setYearStart); + break; + case StructureUtils.LOCALE: + String locale = ReaderUtils.getStringJsonField(parser); + datePatternMap.setLocale(locale); + break; + case StructureUtils.SOURCE_PATTERN: + String sourcePattern = ReaderUtils.getStringJsonField(parser); + datePatternMap.setSourcePattern(sourcePattern); + break; + case StructureUtils.MAPPED_COMPONENTS: + datePatternMappedComponents = ReaderUtils.getArray(parser, this::getMappedComponent); + break; + case StructureUtils.FREQUENCY_DIMENSION: + datePatternMap.setFrequencyDimension(ReaderUtils.getStringJsonField(parser)); + break; + case StructureUtils.TARGET_FREQUENCY_ID: + datePatternMap.setTargetFrequencyId(ReaderUtils.getStringJsonField(parser)); + break; + case StructureUtils.MAPPED_FREQUENCIES: + datePatternMapFreqIds.addAll(ReaderUtils.getListStrings(parser)); + break; + default: + identifiableReader.read(datePatternMap, parser); + break; + } + } + if (CollectionUtils.isNotEmpty(datePatternMappedComponents)) { + mappedComponentsDP.put(datePatternMap, datePatternMappedComponents.get(0)); + } + datePatternFreqDimensionIds.put(datePatternMap, datePatternMapFreqIds); + return datePatternMap; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + @SneakyThrows + private EpochMapImpl getEpochMap(JsonParser parser) { + EpochMapImpl epochMap = new EpochMapImpl(); + List epochMapFreqIds = new ArrayList<>(); + List epochMapMappedComponents = new ArrayList<>(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.BASE_PERIOD: + epochMap.setBasePeriod(ReaderUtils.getInstantObj(parser)); + break; + case StructureUtils.EPOCH_PERIOD: + parser.nextToken(); + epochMap.setEpochPeriod(EnumUtils.getEnumIgnoreCase(EpochPeriodType.class, parser.getText())); + break; + case StructureUtils.RESOLVE_PERIOD: + parser.nextToken(); + epochMap.setResolvePeriod(EnumUtils.getEnumIgnoreCase(ResolvePeriod.class, parser.getText())); + break; + case StructureUtils.YEAR_START: + Optional yearStart = getYearStart(parser); + yearStart.ifPresent(epochMap::setYearStart); + break; + case StructureUtils.MAPPED_COMPONENTS: + epochMapMappedComponents = ReaderUtils.getArray(parser, this::getMappedComponent); + break; + case StructureUtils.FREQUENCY_DIMENSION: + epochMap.setFrequencyDimension(ReaderUtils.getStringJsonField(parser)); + break; + case StructureUtils.MAPPED_FREQUENCIES: + epochMapFreqIds.addAll(ReaderUtils.getListStrings(parser)); + break; + default: + identifiableReader.read(epochMap, parser); + break; + } + } + if (CollectionUtils.isNotEmpty(epochMapMappedComponents)) { + mappedComponentsEpoch.put(epochMap, epochMapMappedComponents.get(0)); + } + epochFreqDimensionIds.put(epochMap, epochMapFreqIds); + return epochMap; + } + + @SneakyThrows + private MappedComponent getMappedComponent(JsonParser parser) { + MappedComponent mappedComponent = new MappedComponent(); + while (parser.nextToken() != JsonToken.END_OBJECT) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.SOURCE: + String sourceId = ReaderUtils.getStringJsonField(parser); + mappedComponent.setSource(sourceId); + break; + case StructureUtils.TARGET: + String targetId = ReaderUtils.getStringJsonField(parser); + mappedComponent.setTarget(targetId); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "FrequencyFormatMapping: " + fieldName); + } + } + return mappedComponent; + } + + + @SneakyThrows + private Optional getYearStart(JsonParser parser) { + int dayOfMonth = -1; + int monthOfYear = -1; + parser.nextToken(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.DAY_OF_MONTH: + parser.nextToken(); + dayOfMonth = parser.getIntValue(); + break; + case StructureUtils.MONTH_OF_YEAR: + parser.nextToken(); + monthOfYear = parser.getIntValue(); + break; + default: + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "YearStart: " + fieldName); + } + } + if (dayOfMonth > 0 && monthOfYear > 0) { + YearStart yearStart = new YearStart(dayOfMonth, monthOfYear); + return Optional.of(yearStart); + } + return Optional.empty(); + } + + @SneakyThrows + private FixedValueMapImpl getFixedValueMap(JsonParser parser) { + FixedValueMapImpl fixedValueMap = new FixedValueMapImpl(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + if (!ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser)) { + return null; + } + String fieldName = parser.getCurrentName(); + if (StructureUtils.VALUE.equals(fieldName)) { + fixedValueMap.setValue(ReaderUtils.getStringJsonField(parser)); + } else { + annotableReader.read(fixedValueMap, parser); + } + } + return fixedValueMap; + } + +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ValueListReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ValueListReader.java new file mode 100644 index 0000000..0c0fab1 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/ValueListReader.java @@ -0,0 +1,98 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.reader.ReaderUtils.getLocalizedField; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.ValueItem; +import com.epam.jsdmx.infomodel.sdmx30.ValueItemImpl; +import com.epam.jsdmx.infomodel.sdmx30.ValueListImpl; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import org.apache.commons.collections.CollectionUtils; + +public class ValueListReader extends MaintainableReader { + + private final AnnotableReader annotableReader; + + public ValueListReader(VersionableReader versionableArtefact, + AnnotableReader annotableReader) { + super(versionableArtefact); + this.annotableReader = annotableReader; + } + + @Override + protected ValueListImpl createMaintainableArtefact() { + return new ValueListImpl(); + } + + @Override + public void readArtefact(JsonParser parser, ValueListImpl valueList) throws IOException { + String fieldName = parser.getCurrentName(); + if (StructureUtils.VALUE_ITEMS.equals(fieldName)) { + List valueItems = ReaderUtils.getArray(parser, (this::getValueItem)); + if (CollectionUtils.isNotEmpty(valueItems)) { + valueList.setItems(valueItems); + } + } else { + throw new IllegalArgumentException(StructureUtils.NO_SUCH_PROPERTY_IN + "ValueList: " + fieldName); + } + } + + @Override + protected String getName() { + return StructureUtils.VALUE_LISTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getValueLists().addAll(artefacts); + } + + private ValueItem getValueItem(JsonParser parser) { + try { + ValueItemImpl valueItem = new ValueItemImpl(); + while (!JsonToken.END_OBJECT.equals(parser.nextToken())) { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldName = parser.getCurrentName(); + switch (fieldName) { + case StructureUtils.ID: + parser.nextToken(); + String id = parser.getText(); + valueItem.setId(id); + break; + case StructureUtils.NAMES: + Map localizedNames = getLocalizedField(parser); + if (localizedNames != null) { + valueItem.setName(new InternationalString(localizedNames)); + } + break; + case StructureUtils.DESCRIPTIONS: + Map localizedDescriptions = getLocalizedField(parser); + if (localizedDescriptions != null) { + valueItem.setDescription(new InternationalString(localizedDescriptions)); + } + break; + case StructureUtils.DESCRIPTION: + case StructureUtils.NAME: + parser.nextToken(); + parser.skipChildren(); + break; + default: + annotableReader.read(valueItem, parser); + break; + } + } + return valueItem; + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } +} \ No newline at end of file diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/VersionableReader.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/VersionableReader.java new file mode 100644 index 0000000..6c97837 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/reader/VersionableReader.java @@ -0,0 +1,41 @@ +package com.epam.jsdmx.json20.structure.reader; + + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; +import com.epam.jsdmx.infomodel.sdmx30.VersionableArtefact; +import com.epam.jsdmx.json20.structure.writer.StructureUtils; + +import com.fasterxml.jackson.core.JsonParser; + +public class VersionableReader { + + private final NameableReader nameableReader; + + public VersionableReader(NameableReader nameableReader) { + this.nameableReader = nameableReader; + } + + public VersionableArtefact read(MaintainableArtefactImpl maintainableArtefact, JsonParser parser) throws IOException { + ReaderUtils.checkIsNotEmptyObjectAndSkipUntilFieldName(parser); + String fieldname = parser.getCurrentName(); + switch (fieldname) { + case StructureUtils.VERSION: + maintainableArtefact.setVersion(Version.createFromString(ReaderUtils.getStringJsonField(parser))); + break; + case StructureUtils.VALID_TO: + maintainableArtefact.setValidTo(ReaderUtils.getStringJsonField(parser)); + break; + case StructureUtils.VALID_FROM: + maintainableArtefact.setValidFrom(ReaderUtils.getStringJsonField(parser)); + break; + default: + nameableReader.read(maintainableArtefact, parser); + break; + } + return maintainableArtefact; + } + +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/AgencySchemeWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/AgencySchemeWriter.java new file mode 100644 index 0000000..ff1beeb --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/AgencySchemeWriter.java @@ -0,0 +1,42 @@ +package com.epam.jsdmx.json20.structure.writer; + + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.AgencyScheme; +import com.epam.jsdmx.infomodel.sdmx30.AgencySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class AgencySchemeWriter extends MaintainableWriter { + + private final OrganisationWriter organisationWriter; + + public AgencySchemeWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + OrganisationWriter organisationWriter) { + super(versionableWriter, linksWriter); + this.organisationWriter = organisationWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, AgencyScheme artefact) throws IOException { + AgencySchemeImpl agencyScheme = (AgencySchemeImpl) artefact; + agencyScheme.setId(StructureUtils.AGENCIES_ID); + super.writeFields(jsonGenerator, agencyScheme); + jsonGenerator.writeBooleanField(StructureUtils.IS_PARTIAL, agencyScheme.isPartial()); + organisationWriter.writeOrganisation(jsonGenerator, artefact.getItems(), StructureUtils.AGENCIES); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getAgencySchemes(); + } + + @Override + protected String getArrayName() { + return StructureUtils.AGENCY_SCHEMES; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/AnnotableWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/AnnotableWriter.java new file mode 100644 index 0000000..dfae423 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/AnnotableWriter.java @@ -0,0 +1,72 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Locale; + +import com.epam.jsdmx.infomodel.sdmx30.AnnotableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.Annotation; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class AnnotableWriter { + + private final LinksWriter linksWriter; + private final List languagePriorities; + + public AnnotableWriter(LinksWriter linksWriter) { + this.linksWriter = linksWriter; + this.languagePriorities = List.of(); + } + + public AnnotableWriter(LinksWriter linksWriter, List languagePriorities) { + this.linksWriter = linksWriter; + this.languagePriorities = languagePriorities; + } + + public void write(JsonGenerator jsonGenerator, AnnotableArtefact annotableArtefact) throws IOException { + write(jsonGenerator, annotableArtefact.getAnnotations()); + } + + protected void write(JsonGenerator jsonGenerator, List annotations) throws IOException { + if (!annotations.isEmpty()) { + jsonGenerator.writeFieldName(StructureUtils.ANNOTATIONS); + writeArray(jsonGenerator, annotations); + } else { + jsonGenerator.writeFieldName(StructureUtils.ANNOTATIONS); + jsonGenerator.writeStartArray(); + jsonGenerator.writeEndArray(); + } + } + + public void writeArray(JsonGenerator jsonGenerator, List annotations) throws IOException { + jsonGenerator.writeStartArray(); + for (Annotation annotation : annotations) { + writeAnnotation(jsonGenerator, annotation); + } + jsonGenerator.writeEndArray(); + } + + protected void writeAnnotation(JsonGenerator jsonGenerator, Annotation annotation) throws IOException { + jsonGenerator.writeStartObject(); + if (annotation.getId() != null) { + jsonGenerator.writeStringField(StructureUtils.ID, annotation.getId()); + } + if (annotation.getTitle() != null) { + jsonGenerator.writeStringField(StructureUtils.TITLE, annotation.getTitle()); + } + if (annotation.getType() != null) { + jsonGenerator.writeStringField(StructureUtils.TYPE, annotation.getType()); + } + if (annotation.getValue() != null) { + jsonGenerator.writeStringField(StructureUtils.VALUE, annotation.getValue()); + } + final var i18nText = annotation.getText(); + if (i18nText != null) { + jsonGenerator.writeStringField(StructureUtils.TEXT, StructureUtils.getLocalisedValue(i18nText, languagePriorities)); + StructureUtils.writeInternationalString(jsonGenerator, i18nText, StructureUtils.TEXTS); + } + linksWriter.writeLinks(jsonGenerator, annotation.getUrl()); + jsonGenerator.writeEndObject(); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/AttributeListWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/AttributeListWriter.java new file mode 100644 index 0000000..599cba1 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/AttributeListWriter.java @@ -0,0 +1,123 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.AttributeRelationship; +import com.epam.jsdmx.infomodel.sdmx30.DataAttribute; +import com.epam.jsdmx.infomodel.sdmx30.DimensionRelationship; +import com.epam.jsdmx.infomodel.sdmx30.GroupRelationship; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.MeasureRelationship; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeRef; +import com.epam.jsdmx.infomodel.sdmx30.ObservationRelationship; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = false) +public class AttributeListWriter extends IdentifiableWriter { + + private final ConceptRoleWriter conceptRoleWriter; + private final ComponentWriter componentWriter; + + public AttributeListWriter(AnnotableWriter annotableWriter, ConceptRoleWriter conceptRoleWriter, ComponentWriter componentWriter) { + super(annotableWriter); + this.conceptRoleWriter = conceptRoleWriter; + this.componentWriter = componentWriter; + } + + @Override + public void write(JsonGenerator jsonGenerator, IdentifiableArtefact identifiableArtefact) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.ATTRIBUTE_LIST); + if (identifiableArtefact == null) { + jsonGenerator.writeNull(); + return; + } + AttributeDescriptorImpl attributeDescriptor = (AttributeDescriptorImpl) identifiableArtefact; + attributeDescriptor.setId(StructureUtils.ATTRIBUTE_DESCRIPTOR_ID); + jsonGenerator.writeStartObject(); + super.write(jsonGenerator, attributeDescriptor); + List attributeDescriptorComponents = attributeDescriptor.getComponents(); + writeDataAttributeUsage(jsonGenerator, attributeDescriptor.getMetadataAttributes()); + writeDataAttributes(jsonGenerator, attributeDescriptorComponents); + jsonGenerator.writeEndObject(); + } + + private void writeDataAttributeUsage(JsonGenerator jsonGenerator, List metadata) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.METADATA_ATTRIBUTE_USAGES); + jsonGenerator.writeStartArray(); + if (metadata != null && !metadata.isEmpty()) { + for (MetadataAttributeRef attributeRef : metadata) { + if (attributeRef != null) { + jsonGenerator.writeStartObject(); + super.getAnnotableWriter() + .write(jsonGenerator, attributeRef); + jsonGenerator.writeStringField(StructureUtils.METADATA_ATTRIBUTE_REFERENCE, attributeRef.getId()); + writeAttributeRelationship(jsonGenerator, attributeRef.getMetadataRelationship()); + jsonGenerator.writeEndObject(); + } + } + } + jsonGenerator.writeEndArray(); + } + + private void writeDataAttributes(JsonGenerator jsonGenerator, List attributeDescriptorComponents) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.ATTRIBUTES); + jsonGenerator.writeStartArray(); + if (attributeDescriptorComponents != null && !attributeDescriptorComponents.isEmpty()) { + for (DataAttribute dataAttribute : attributeDescriptorComponents) { + if (dataAttribute != null) { + jsonGenerator.writeStartObject(); + componentWriter.write(jsonGenerator, dataAttribute); + jsonGenerator.writeBooleanField(StructureUtils.IS_MANDATORY, dataAttribute.isMandatory()); + conceptRoleWriter.write(jsonGenerator, dataAttribute.getConceptRoles()); + writeAttributeRelationship(jsonGenerator, dataAttribute.getAttributeRelationship()); + writeMeasureRelationship(jsonGenerator, dataAttribute.getMeasureRelationship()); + jsonGenerator.writeEndObject(); + } + } + } + jsonGenerator.writeEndArray(); + } + + private void writeAttributeRelationship(JsonGenerator jsonGenerator, AttributeRelationship attributeRelationship) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.ATTRIBUTE_RELATIONSHIP); + jsonGenerator.writeStartObject(); + if (attributeRelationship instanceof DimensionRelationship) { + DimensionRelationship dimensionRelationship = (DimensionRelationship) attributeRelationship; + jsonGenerator.writeFieldName(StructureUtils.DIMENSIONS); + List dimensions = dimensionRelationship.getDimensions(); + jsonGenerator.writeStartArray(); + for (String dimension : dimensions) { + jsonGenerator.writeString(dimension); + } + jsonGenerator.writeEndArray(); + + } else if (attributeRelationship instanceof ObservationRelationship) { + jsonGenerator.writeFieldName(StructureUtils.OBSERVATION); + jsonGenerator.writeStartObject(); + jsonGenerator.writeEndObject(); + } else if (attributeRelationship instanceof GroupRelationship) { + GroupRelationship groupRelationship = (GroupRelationship) attributeRelationship; + jsonGenerator.writeStringField(StructureUtils.GROUP, groupRelationship.getGroupKey()); + } else { + jsonGenerator.writeFieldName(StructureUtils.NONE); + jsonGenerator.writeStartObject(); + jsonGenerator.writeEndObject(); + } + jsonGenerator.writeEndObject(); + } + + private void writeMeasureRelationship(JsonGenerator jsonGenerator, MeasureRelationship measureRelationship) throws IOException { + if (measureRelationship != null) { + jsonGenerator.writeFieldName(StructureUtils.MEASURE_RELATIONSHIP); + jsonGenerator.writeStartArray(); + for (String measure : measureRelationship.getMeasures()) { + jsonGenerator.writeString(measure); + } + jsonGenerator.writeEndArray(); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/BaseWriterJson.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/BaseWriterJson.java new file mode 100644 index 0000000..0292f17 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/BaseWriterJson.java @@ -0,0 +1,20 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.OutputStream; + +import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; + +public class BaseWriterJson { + + protected final JsonGenerator jsonGenerator; + + @SneakyThrows + protected BaseWriterJson(ObjectMapper mapper, + OutputStream outputStream) { + this.jsonGenerator = mapper.getFactory().createGenerator(outputStream, JsonEncoding.UTF8); + } + +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CategorisationWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CategorisationWriter.java new file mode 100644 index 0000000..a8dfb41 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CategorisationWriter.java @@ -0,0 +1,47 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Categorisation; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; + + +public class CategorisationWriter extends MaintainableWriter { + + private final ReferenceAdapter referenceAdapter; + + public CategorisationWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + ReferenceAdapter referenceAdapter) { + super(versionableWriter, linksWriter); + this.referenceAdapter = referenceAdapter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, Categorisation categorisation) throws IOException { + super.writeFields(jsonGenerator, categorisation); + writeArtefactReference(jsonGenerator, categorisation.getCategorizedArtefact(), StructureUtils.SOURCE); + writeArtefactReference(jsonGenerator, categorisation.getCategorizedBy(), StructureUtils.TARGET); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getCategorisations(); + } + + @Override + protected String getArrayName() { + return StructureUtils.CATEGORISATIONS; + } + + private void writeArtefactReference(JsonGenerator jsonGenerator, ArtefactReference structure, String fieldName) throws IOException { + if (structure != null) { + jsonGenerator.writeStringField(fieldName, referenceAdapter.toAdaptedUrn(structure)); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CategorySchemeMapWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CategorySchemeMapWriter.java new file mode 100644 index 0000000..45be521 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CategorySchemeMapWriter.java @@ -0,0 +1,44 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeMap; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class CategorySchemeMapWriter extends MaintainableWriter { + + private final AnnotableWriter annotableWriter; + private final ItemMapWriter itemMapWriter; + + public CategorySchemeMapWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + AnnotableWriter annotableWriter, ItemMapWriter itemMapWriter) { + super(versionableWriter, linksWriter); + this.annotableWriter = annotableWriter; + this.itemMapWriter = itemMapWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, CategorySchemeMap categorySchemeMap) throws IOException { + super.writeFields(jsonGenerator, categorySchemeMap); + List itemMaps = categorySchemeMap.getItemMaps(); + itemMapWriter.writeItemMaps(jsonGenerator, itemMaps, annotableWriter); + itemMapWriter.writeSource(jsonGenerator, categorySchemeMap.getSource()); + itemMapWriter.writeTarget(jsonGenerator, categorySchemeMap.getTarget()); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getCategorySchemeMaps(); + } + + @Override + protected String getArrayName() { + return StructureUtils.CATEGORY_SCHEME_MAPS; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CategorySchemeWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CategorySchemeWriter.java new file mode 100644 index 0000000..8f24584 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CategorySchemeWriter.java @@ -0,0 +1,56 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Category; +import com.epam.jsdmx.infomodel.sdmx30.CategoryScheme; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class CategorySchemeWriter extends MaintainableWriter { + + private final NameableWriter nameableWriter; + + public CategorySchemeWriter(VersionableWriter versionableWriter, LinksWriter linksWriter, NameableWriter nameableWriter) { + super(versionableWriter, linksWriter); + this.nameableWriter = nameableWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, CategoryScheme categoryScheme) throws IOException { + super.writeFields(jsonGenerator, categoryScheme); + jsonGenerator.writeBooleanField(StructureUtils.IS_PARTIAL, categoryScheme.isPartial()); + writeCategoriesList(jsonGenerator, categoryScheme.getItems()); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getCategorySchemes(); + } + + @Override + protected String getArrayName() { + return StructureUtils.CATEGORY_SCHEMES; + } + + private void writeCategoriesList(JsonGenerator jsonGenerator, List categoryScheme) throws IOException { + if (categoryScheme != null) { + jsonGenerator.writeFieldName(StructureUtils.CATEGORIES); + jsonGenerator.writeStartArray(); + if (!categoryScheme.isEmpty()) { + for (Category category : categoryScheme) { + jsonGenerator.writeStartObject(); + nameableWriter.write(jsonGenerator, category); + if (!category.getHierarchy().isEmpty()) { + writeCategoriesList(jsonGenerator, category.getHierarchy()); + } + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodeWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodeWriter.java new file mode 100644 index 0000000..1f3303f --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodeWriter.java @@ -0,0 +1,43 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Code; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections4.CollectionUtils; + +public abstract class CodeWriter { + + public void writeCodes(JsonGenerator jsonGenerator, + List codes, + String name, + NameableWriter nameableWriter) throws IOException { + if (CollectionUtils.isNotEmpty(codes)) { + jsonGenerator.writeFieldName(name); + jsonGenerator.writeStartArray(); + for (T code : codes) { + write(jsonGenerator, code, nameableWriter); + } + jsonGenerator.writeEndArray(); + } + } + + public void write(JsonGenerator jsonGenerator, + T code, + NameableWriter nameableWriter) throws IOException { + jsonGenerator.writeStartObject(); + writeFields(jsonGenerator, code, nameableWriter); + jsonGenerator.writeEndObject(); + } + + public void writeFields(JsonGenerator jsonGenerator, + T code, + NameableWriter nameableWriter) throws IOException { + nameableWriter.write(jsonGenerator, code); + if (code.getParentId() != null) { + jsonGenerator.writeStringField(StructureUtils.PARENT, code.getParentId()); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodeWriterImpl.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodeWriterImpl.java new file mode 100644 index 0000000..308ef70 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodeWriterImpl.java @@ -0,0 +1,6 @@ +package com.epam.jsdmx.json20.structure.writer; + +import com.epam.jsdmx.infomodel.sdmx30.Code; + +public class CodeWriterImpl extends CodeWriter { +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodelistExtensionWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodelistExtensionWriter.java new file mode 100644 index 0000000..3ee5db0 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodelistExtensionWriter.java @@ -0,0 +1,110 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.CascadeValue; +import com.epam.jsdmx.infomodel.sdmx30.CodeSelection; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.ExclusiveCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.InclusiveCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberValue; +import com.epam.jsdmx.infomodel.sdmx30.StreamUtils; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +public class CodelistExtensionWriter { + + private final ReferenceAdapter referenceAdapter; + + public CodelistExtensionWriter(ReferenceAdapter referenceAdapter) { + this.referenceAdapter = referenceAdapter; + } + + public void writeCodeListExtentions(JsonGenerator jsonGenerator, List extensions) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.CODE_LIST_EXTENSIONS); + jsonGenerator.writeStartArray(); + if (CollectionUtils.isNotEmpty(extensions)) { + for (CodelistExtension codelistExtension : extensions) { + if (codelistExtension != null) { + write(jsonGenerator, codelistExtension); + } + } + } + jsonGenerator.writeEndArray(); + } + + public void write(JsonGenerator jsonGenerator, CodelistExtension codelistExtension) throws IOException { + jsonGenerator.writeStartObject(); + writeFields(jsonGenerator, codelistExtension); + jsonGenerator.writeEndObject(); + } + + protected void writeFields(JsonGenerator jsonGenerator, CodelistExtension codelistExtension) throws IOException { + jsonGenerator.writeStringField(StructureUtils.PREFIX, codelistExtension.getPrefix()); + ArtefactReference maintainableReference = codelistExtension.getCodelist(); + if (maintainableReference != null) { + jsonGenerator.writeStringField(StructureUtils.CODE_LIST, referenceAdapter.toAdaptedUrn(maintainableReference)); + } + if (codelistExtension.getCodeSelection() instanceof InclusiveCodeSelectionImpl) { + writeCodeSelection(jsonGenerator, codelistExtension.getCodeSelection(), StructureUtils.INCLUSIVE_CODE_SELECTION); + } else if (codelistExtension.getCodeSelection() instanceof ExclusiveCodeSelectionImpl) { + writeCodeSelection(jsonGenerator, codelistExtension.getCodeSelection(), StructureUtils.EXCLUSIVE_CODE_SELECTION); + } + } + + private void writeCodeSelection(JsonGenerator jsonGenerator, CodeSelection codeSelection, String codeSelectionType) throws IOException { + jsonGenerator.writeFieldName(codeSelectionType); + jsonGenerator.writeStartObject(); + List members = codeSelection.getMembers(); + if (members != null && !members.isEmpty()) { + if (CollectionUtils.size(members) == 1 && StringUtils.endsWith(members.get(0).getValue(), "%")) { + writeWildcardedMemberValues(jsonGenerator, members); + } else { + writeMemberValues(jsonGenerator, members); + } + } + jsonGenerator.writeEndObject(); + } + + private void writeMemberValues(JsonGenerator jsonGenerator, List members) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.MEMBER_VALUES); + jsonGenerator.writeStartArray(); + List nonNullMemberValues = StreamUtils.streamOfNullable(members) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (!nonNullMemberValues.isEmpty()) { + for (MemberValue memberValue : nonNullMemberValues) { + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField(StructureUtils.VALUE, memberValue.getValue()); + CascadeValue cascadeValue = memberValue.getCascadeValue(); + if (StructureUtils.CASCADE_VALUE_TYPE_STRING.get(cascadeValue) != null) { + jsonGenerator.writeStringField(StructureUtils.CASCADE_VALUES, StructureUtils.CASCADE_VALUE_TYPE_STRING.get(cascadeValue)); + } + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + + private void writeWildcardedMemberValues(JsonGenerator jsonGenerator, List members) throws IOException { + List wildcardedMemberValues = members.stream() + .map(MemberValue::getValue) + .collect(Collectors.toList()); + jsonGenerator.writeFieldName(StructureUtils.WILDCARDED_MEMBER_VALUES); + jsonGenerator.writeStartArray(); + if (!wildcardedMemberValues.isEmpty()) { + for (String member : wildcardedMemberValues) { + jsonGenerator.writeString(member); + } + } + jsonGenerator.writeEndArray(); + } + +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodelistWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodelistWriter.java new file mode 100644 index 0000000..48eb0b3 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CodelistWriter.java @@ -0,0 +1,57 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Code; +import com.epam.jsdmx.infomodel.sdmx30.Codelist; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class CodelistWriter extends MaintainableWriter { + + private final CodeWriterImpl codeWriter; + private final CodelistExtensionWriter extensionWriter; + private final NameableWriter nameableWriter; + + public CodelistWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + CodeWriterImpl codeWriter, + CodelistExtensionWriter extensionWriter, + NameableWriter nameableWriter) { + super(versionableWriter, linksWriter); + this.codeWriter = codeWriter; + this.extensionWriter = extensionWriter; + this.nameableWriter = nameableWriter; + } + + @Override + public Optional getWritableArtefactStructureClass() { + return Optional.of(StructureClassImpl.CODELIST); + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, Codelist codelist) throws IOException { + super.writeFields(jsonGenerator, codelist); + + jsonGenerator.writeBooleanField(StructureUtils.IS_PARTIAL, codelist.isPartial()); + codeWriter.writeCodes(jsonGenerator, (List) codelist.getItems(), StructureUtils.CODES, nameableWriter); + extensionWriter.writeCodeListExtentions(jsonGenerator, codelist.getExtensions()); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getCodelists(); + } + + @Override + protected String getArrayName() { + return StructureUtils.CODE_LISTS; + } + +} \ No newline at end of file diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ComponentWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ComponentWriter.java new file mode 100644 index 0000000..22847ca --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ComponentWriter.java @@ -0,0 +1,33 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.Component; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class ComponentWriter { + + private final IdentifiableWriter identifiableWriter; + private final RepresentationWriter representationWriter; + private final ReferenceAdapter referenceAdapter; + + public ComponentWriter(IdentifiableWriter identifiableWriter, RepresentationWriter representationWriter, ReferenceAdapter referenceAdapter) { + this.identifiableWriter = identifiableWriter; + this.representationWriter = representationWriter; + this.referenceAdapter = referenceAdapter; + } + + public void write(JsonGenerator jsonGenerator, Component component) throws IOException { + identifiableWriter.write(jsonGenerator, component); + if (component.getConceptIdentity() != null) { + jsonGenerator.writeStringField(StructureUtils.CONCEPT_IDENTITY, referenceAdapter.toAdaptedUrn(component.getConceptIdentity())); + } + final Representation localRepresentation = component.getLocalRepresentation(); + if (localRepresentation != null) { + representationWriter.writeRepresentation(jsonGenerator, localRepresentation, StructureUtils.LOCAL_REPRESENTATION); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ConceptRoleWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ConceptRoleWriter.java new file mode 100644 index 0000000..a3a3ecd --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ConceptRoleWriter.java @@ -0,0 +1,29 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class ConceptRoleWriter { + + private final ReferenceAdapter referenceAdapter; + + public ConceptRoleWriter(ReferenceAdapter referenceAdapter) { + this.referenceAdapter = referenceAdapter; + } + + public void write(JsonGenerator jsonGenerator, List conceptRoles) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.CONCEPT_ROLES); + jsonGenerator.writeStartArray(); + if (conceptRoles != null && !conceptRoles.isEmpty()) { + for (ArtefactReference structureItemReference : conceptRoles) { + jsonGenerator.writeString(referenceAdapter.toAdaptedUrn(structureItemReference)); + } + } + jsonGenerator.writeEndArray(); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ConceptSchemeMapWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ConceptSchemeMapWriter.java new file mode 100644 index 0000000..68a56f9 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ConceptSchemeMapWriter.java @@ -0,0 +1,45 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeMap; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class ConceptSchemeMapWriter extends MaintainableWriter { + + private final AnnotableWriter annotableWriter; + private final ItemMapWriter itemMapWriter; + + public ConceptSchemeMapWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + AnnotableWriter annotableWriter, + ItemMapWriter itemMapWriter) { + super(versionableWriter, linksWriter); + this.annotableWriter = annotableWriter; + this.itemMapWriter = itemMapWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, ConceptSchemeMap conceptSchemeMap) throws IOException { + super.writeFields(jsonGenerator, conceptSchemeMap); + List itemMaps = conceptSchemeMap.getItemMaps(); + itemMapWriter.writeItemMaps(jsonGenerator, itemMaps, annotableWriter); + itemMapWriter.writeSource(jsonGenerator, conceptSchemeMap.getSource()); + itemMapWriter.writeTarget(jsonGenerator, conceptSchemeMap.getTarget()); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getConceptSchemeMaps(); + } + + @Override + protected String getArrayName() { + return StructureUtils.CONCEPT_SCHEME_MAPS; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ConceptSchemeWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ConceptSchemeWriter.java new file mode 100644 index 0000000..757c0f6 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ConceptSchemeWriter.java @@ -0,0 +1,85 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Concept; +import com.epam.jsdmx.infomodel.sdmx30.ConceptScheme; +import com.epam.jsdmx.infomodel.sdmx30.IsoConceptReference; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class ConceptSchemeWriter extends MaintainableWriter { + + private final NameableWriter nameableWriter; + private final RepresentationWriter representationWriter; + + public ConceptSchemeWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + NameableWriter nameableWriter, + RepresentationWriter representationWriter) { + super(versionableWriter, linksWriter); + this.nameableWriter = nameableWriter; + this.representationWriter = representationWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, ConceptScheme conceptScheme) throws IOException { + super.writeFields(jsonGenerator, conceptScheme); + List conceptSchemeItems = conceptScheme.getItems(); + if (conceptSchemeItems != null) { + jsonGenerator.writeFieldName(StructureUtils.CONCEPTS); + jsonGenerator.writeStartArray(); + if (!conceptSchemeItems.isEmpty()) { + for (Concept concept : conceptSchemeItems) { + jsonGenerator.writeStartObject(); + nameableWriter.write(jsonGenerator, concept); + + representationWriter.writeRepresentation(jsonGenerator, concept.getCoreRepresentation(), StructureUtils.CORE_REPRESENTATION); + + IsoConceptReference isoConceptReference = concept.getIsoConceptReference(); + writeIsoConceptReference(jsonGenerator, isoConceptReference); + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + jsonGenerator.writeBooleanField(StructureUtils.IS_PARTIAL, conceptScheme.isPartial()); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getConceptSchemes(); + } + + @Override + protected String getArrayName() { + return StructureUtils.CONCEPT_SCHEMES; + } + + private void writeIsoConceptReference(JsonGenerator jsonGenerator, IsoConceptReference isoConceptReference) throws IOException { + if (isoConceptReference != null) { + jsonGenerator.writeFieldName(StructureUtils.ISO_CONCEPT_REFERENCE); + jsonGenerator.writeStartObject(); + + String schemeId = isoConceptReference.getSchemeId(); + if (schemeId != null) { + jsonGenerator.writeStringField(StructureUtils.CONCEPT_SCHEME_ID, schemeId); + } + + String conceptId = isoConceptReference.getConceptId(); + if (conceptId != null) { + jsonGenerator.writeStringField(StructureUtils.CONCEPT_ID, conceptId); + } + + String agency = isoConceptReference.getAgency(); + if (agency != null) { + jsonGenerator.writeStringField(StructureUtils.CONCEPT_AGENCY, agency); + } + + jsonGenerator.writeEndObject(); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ContactsWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ContactsWriter.java new file mode 100644 index 0000000..edafc64 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ContactsWriter.java @@ -0,0 +1,76 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.net.URI; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Contact; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections.CollectionUtils; + +public class ContactsWriter { + + public void writeContacts(JsonGenerator jsonGenerator, List contacts) throws IOException { + if (CollectionUtils.isNotEmpty(contacts)) { + jsonGenerator.writeFieldName(StructureUtils.CONTACTS); + jsonGenerator.writeStartArray(); + for (Contact contact : contacts) { + if (contact != null) { + jsonGenerator.writeStartObject(); + + String name = contact.getName(); + if (name != null) { + jsonGenerator.writeStringField(StructureUtils.NAME, name); + } + + String organizationUnit = contact.getOrganizationUnit(); + writeOrganisationUnit(jsonGenerator, organizationUnit); + + InternationalString responsibility = contact.getResponsibility(); + StructureUtils.writeInternationalString(jsonGenerator, responsibility, StructureUtils.ROLE); + + String telephone = contact.getTelephone(); + writeOneStringArray(jsonGenerator, telephone, StructureUtils.TELEPHONES); + + String fax = contact.getFax(); + writeOneStringArray(jsonGenerator, fax, StructureUtils.FAXES); + + String x400 = contact.getX400(); + writeOneStringArray(jsonGenerator, x400, StructureUtils.X_400_S); + + URI uri = contact.getUri(); + writeURI(jsonGenerator, uri); + + String email = contact.getEmail(); + writeOneStringArray(jsonGenerator, email, StructureUtils.EMAILS); + + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } + + private void writeOrganisationUnit(JsonGenerator jsonGenerator, String organizationUnit) throws IOException { + if (organizationUnit != null) { + jsonGenerator.writeStringField(StructureUtils.DEPARTMENT, organizationUnit); + } + } + + private void writeURI(JsonGenerator jsonGenerator, URI uri) throws IOException { + if (uri != null) { + writeOneStringArray(jsonGenerator, uri.toString(), StructureUtils.URIS); + } + } + + private void writeOneStringArray(JsonGenerator jsonGenerator, String parameter, String parameterName) throws IOException { + jsonGenerator.writeFieldName(parameterName); + jsonGenerator.writeStartArray(); + if (parameter != null) { + jsonGenerator.writeString(parameter); + } + jsonGenerator.writeEndArray(); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CubeRegionWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CubeRegionWriter.java new file mode 100644 index 0000000..6bc48da --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/CubeRegionWriter.java @@ -0,0 +1,60 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.CubeRegion; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionKey; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections4.CollectionUtils; + +public class CubeRegionWriter { + private final MemberSelectionWriter memberSelectionWriter; + private final DateTimeWriter dateTimeWriter; + + private final AnnotableWriter annotableWriter; + + public CubeRegionWriter(MemberSelectionWriter memberSelectionWriter, + DateTimeWriter dateTimeWriter, + AnnotableWriter annotableWriter) { + this.memberSelectionWriter = memberSelectionWriter; + this.dateTimeWriter = dateTimeWriter; + this.annotableWriter = annotableWriter; + } + + public void write(JsonGenerator jsonGenerator, List cubeRegions) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.CUBE_REGIONS); + jsonGenerator.writeStartArray(); + if (CollectionUtils.isNotEmpty(cubeRegions)) { + for (CubeRegion cubeRegion : cubeRegions) { + jsonGenerator.writeStartObject(); + jsonGenerator.writeBooleanField(StructureUtils.INCLUDE, cubeRegion.isIncluded()); + memberSelectionWriter.writeMemberSelections(jsonGenerator, cubeRegion.getMemberSelections()); + writeKeyValues(jsonGenerator, cubeRegion.getCubeRegionKeys()); + annotableWriter.write(jsonGenerator, cubeRegion); + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + + + private void writeKeyValues(JsonGenerator jsonGenerator, List cubeRegionKeys) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.KEY_VALUES); + jsonGenerator.writeStartArray(); + if (CollectionUtils.isNotEmpty(cubeRegionKeys)) { + for (CubeRegionKey cubeRegionKey : cubeRegionKeys) { + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField(StructureUtils.ID, cubeRegionKey.getComponentId()); + jsonGenerator.writeBooleanField(StructureUtils.INCLUDE, cubeRegionKey.isIncluded()); + jsonGenerator.writeBooleanField(StructureUtils.REMOVE_PREFIX, cubeRegionKey.isRemovePrefix()); + dateTimeWriter.writeValidDate(jsonGenerator, cubeRegionKey.getValidFrom(), StructureUtils.VALID_FROM); + dateTimeWriter.writeValidDate(jsonGenerator, cubeRegionKey.getValidTo(), StructureUtils.VALID_TO); + memberSelectionWriter.writeSelectionValues(jsonGenerator, cubeRegionKey.getSelectionValues()); + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataConstraintWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataConstraintWriter.java new file mode 100644 index 0000000..fe87843 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataConstraintWriter.java @@ -0,0 +1,115 @@ +package com.epam.jsdmx.json20.structure.writer; + +import static com.epam.jsdmx.json20.structure.writer.StructureUtils.CONSTRAINT_ROLE_STRING; + +import java.io.IOException; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendar; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections.CollectionUtils; + + +public class DataConstraintWriter extends MaintainableWriter { + + private final CubeRegionWriter cubeRegionWriter; + private final DataKeySetsWriter dataKeySetsWriter; + private final ReferenceAdapter referenceAdapter; + + public DataConstraintWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + CubeRegionWriter cubeRegionWriter, + DataKeySetsWriter dataKeySetsWriter, + ReferenceAdapter referenceAdapter) { + super(versionableWriter, linksWriter); + this.cubeRegionWriter = cubeRegionWriter; + this.dataKeySetsWriter = dataKeySetsWriter; + this.referenceAdapter = referenceAdapter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, DataConstraint dataConstraint) throws IOException { + super.writeFields(jsonGenerator, dataConstraint); + if (dataConstraint.getConstraintRoleType() != null) { + jsonGenerator.writeStringField(StructureUtils.ROLE, CONSTRAINT_ROLE_STRING.get(dataConstraint.getConstraintRoleType())); + } + + List constrainedArtefacts = dataConstraint.getConstrainedArtefacts(); + writeConstrainedArtefacts(jsonGenerator, constrainedArtefacts); + + writeReleaseCalendar(jsonGenerator, dataConstraint.getReleaseCalendar()); + + dataKeySetsWriter.write(jsonGenerator, dataConstraint.getDataContentKeys()); + + cubeRegionWriter.write(jsonGenerator, dataConstraint.getCubeRegions()); + } + + private void writeConstrainedArtefacts(JsonGenerator jsonGenerator, List constrainedArtefacts) throws IOException { + if (CollectionUtils.isNotEmpty(constrainedArtefacts)) { + jsonGenerator.writeFieldName(StructureUtils.CONSTRAINT_ATTACHMENT); + jsonGenerator.writeStartObject(); + Optional providerRef = StructureUtils.getArtefactReferenceByStructureClass( + constrainedArtefacts, + StructureClassImpl.DATA_PROVIDER + ); + if (providerRef.isPresent()) { + jsonGenerator.writeStringField(StructureUtils.DATA_PROVIDER, referenceAdapter.toAdaptedUrn(providerRef.get())); + } + + List dataStructures = StructureUtils.getArtefactReferencesByStructureClass( + constrainedArtefacts, + StructureClassImpl.DATA_STRUCTURE + ); + StructureUtils.writeArtefactReferences(jsonGenerator, dataStructures, StructureUtils.DATA_STRUCTURES, referenceAdapter); + + List dataFlows = StructureUtils.getArtefactReferencesByStructureClass(constrainedArtefacts, StructureClassImpl.DATAFLOW); + StructureUtils.writeArtefactReferences(jsonGenerator, dataFlows, StructureUtils.DATAFLOWS, referenceAdapter); + + List provisionAgreements = StructureUtils.getArtefactReferencesByStructureClass( + constrainedArtefacts, + StructureClassImpl.PROVISION_AGREEMENT + ); + StructureUtils.writeArtefactReferences(jsonGenerator, provisionAgreements, StructureUtils.PROVISION_AGREEMENTS, referenceAdapter); + + jsonGenerator.writeEndObject(); + } + } + + private void writeReleaseCalendar(JsonGenerator jsonGenerator, ReleaseCalendar releaseCalendar) throws IOException { + if (releaseCalendar != null) { + jsonGenerator.writeFieldName(StructureUtils.RELEASE_CALENDAR); + jsonGenerator.writeStartObject(); + String tolerance = releaseCalendar.getTolerance(); + if (tolerance != null) { + jsonGenerator.writeStringField(StructureUtils.TOLERANCE, tolerance); + } + String offset = releaseCalendar.getOffset(); + if (offset != null) { + jsonGenerator.writeStringField(StructureUtils.OFFSET, offset); + } + String periodicity = releaseCalendar.getPeriodicity(); + if (periodicity != null) { + jsonGenerator.writeStringField(StructureUtils.PERIODICITY, periodicity); + } + jsonGenerator.writeEndObject(); + } + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getDataConstraints(); + } + + @Override + protected String getArrayName() { + return StructureUtils.DATA_CONSTRAINTS; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataConsumerSchemeWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataConsumerSchemeWriter.java new file mode 100644 index 0000000..fc9cd90 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataConsumerSchemeWriter.java @@ -0,0 +1,47 @@ +package com.epam.jsdmx.json20.structure.writer; + + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerScheme; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class DataConsumerSchemeWriter extends MaintainableWriter { + + private final OrganisationWriter organisationWriter; + + public DataConsumerSchemeWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + OrganisationWriter organisationWriter) { + super(versionableWriter, linksWriter); + this.organisationWriter = organisationWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, DataConsumerScheme dataConsumerScheme) throws IOException { + DataConsumerSchemeImpl dataConsumerSchemeImpl = (DataConsumerSchemeImpl) dataConsumerScheme; + dataConsumerSchemeImpl.setId(StructureUtils.DATA_CONSUMERS_ID); + dataConsumerSchemeImpl.setVersion(Version.createFromString(StructureUtils.DEFAULT_VERSION)); + super.writeFields(jsonGenerator, dataConsumerSchemeImpl); + Boolean isPartial = dataConsumerScheme.isPartial(); + if (isPartial != null) { + jsonGenerator.writeBooleanField(StructureUtils.IS_PARTIAL, isPartial); + } + organisationWriter.writeOrganisation(jsonGenerator, dataConsumerScheme.getItems(), StructureUtils.DATA_CONSUMERS); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getDataConsumerSchemes(); + } + + @Override + protected String getArrayName() { + return StructureUtils.DATA_CONSUMER_SCHEMES; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataKeySetsWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataKeySetsWriter.java new file mode 100644 index 0000000..113cbe5 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataKeySetsWriter.java @@ -0,0 +1,90 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.ComponentValue; +import com.epam.jsdmx.infomodel.sdmx30.DataKey; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySet; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections.CollectionUtils; + +public class DataKeySetsWriter { + private final AnnotableWriter annotableWriter; + private final MemberSelectionWriter memberSelectionWriter; + private final DateTimeWriter dateTimeWriter; + + public DataKeySetsWriter(AnnotableWriter annotableWriter, MemberSelectionWriter memberSelectionWriter, DateTimeWriter dateTimeWriter) { + this.annotableWriter = annotableWriter; + this.memberSelectionWriter = memberSelectionWriter; + this.dateTimeWriter = dateTimeWriter; + } + + public void write(JsonGenerator jsonGenerator, List dataKeySets) throws IOException { + if (CollectionUtils.isNotEmpty(dataKeySets)) { + jsonGenerator.writeFieldName(StructureUtils.DATA_KEY_SETS); + jsonGenerator.writeStartArray(); + for (DataKeySet dataKeySet : dataKeySets) { + if (dataKeySet != null) { + jsonGenerator.writeStartObject(); + + jsonGenerator.writeBooleanField(StructureUtils.IS_INCLUDED, dataKeySet.isIncluded()); + + writeDataKeys(jsonGenerator, dataKeySet.getKeys()); + + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } + + public void writeDataKeys(JsonGenerator jsonGenerator, List keys) throws IOException { + if (CollectionUtils.isNotEmpty(keys)) { + jsonGenerator.writeFieldName(StructureUtils.KEYS); + jsonGenerator.writeStartArray(); + for (DataKey dataKey : keys) { + if (dataKey != null) { + jsonGenerator.writeStartObject(); + + annotableWriter.write(jsonGenerator, dataKey); + + writeKeyValues(jsonGenerator, dataKey.getKeyValues()); + memberSelectionWriter.writeMemberSelections(jsonGenerator, dataKey.getMemberSelections()); + jsonGenerator.writeBooleanField(StructureUtils.INCLUDE, dataKey.isIncluded()); + dateTimeWriter.writeValidDate(jsonGenerator, dataKey.getValidFrom(), StructureUtils.VALID_FROM); + dateTimeWriter.writeValidDate(jsonGenerator, dataKey.getValidTo(), StructureUtils.VALID_TO); + + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } + + public void writeKeyValues(JsonGenerator jsonGenerator, List keyValues) throws IOException { + if (CollectionUtils.isNotEmpty(keyValues)) { + jsonGenerator.writeFieldName(StructureUtils.KEY_VALUES); + jsonGenerator.writeStartArray(); + for (ComponentValue componentValue : keyValues) { + if (componentValue != null) { + jsonGenerator.writeStartObject(); + + if (componentValue.getComponentId() != null) { + jsonGenerator.writeStringField(StructureUtils.ID, componentValue.getComponentId()); + } + jsonGenerator.writeBooleanField(StructureUtils.INCLUDE, componentValue.isIncluded()); + jsonGenerator.writeBooleanField(StructureUtils.REMOVE_PREFIX, componentValue.isRemovePrefix()); + if (componentValue.getValue() != null) { + jsonGenerator.writeStringField(StructureUtils.VALUE, componentValue.getValue()); + } + + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } + +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataProviderSchemeWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataProviderSchemeWriter.java new file mode 100644 index 0000000..e966f86 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataProviderSchemeWriter.java @@ -0,0 +1,44 @@ +package com.epam.jsdmx.json20.structure.writer; + + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderScheme; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class DataProviderSchemeWriter extends MaintainableWriter { + + private final OrganisationWriter organisationWriter; + + public DataProviderSchemeWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + OrganisationWriter organisationWriter) { + super(versionableWriter, linksWriter); + this.organisationWriter = organisationWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, DataProviderScheme dataProviderScheme) throws IOException { + DataProviderSchemeImpl providerScheme = (DataProviderSchemeImpl) dataProviderScheme; + providerScheme.setId(StructureUtils.DATA_PROVIDERS_ID); + providerScheme.setVersion(Version.createFromString(StructureUtils.DEFAULT_VERSION)); + super.writeFields(jsonGenerator, providerScheme); + jsonGenerator.writeBooleanField(StructureUtils.IS_PARTIAL, dataProviderScheme.isPartial()); + organisationWriter.writeOrganisation(jsonGenerator, dataProviderScheme.getItems(), StructureUtils.DATA_PROVIDERS); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getDataProviderSchemes(); + } + + @Override + protected String getArrayName() { + return StructureUtils.DATA_PROVIDER_SCHEMES; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataStructureComponentsUtils.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataStructureComponentsUtils.java new file mode 100644 index 0000000..c2b40cd --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataStructureComponentsUtils.java @@ -0,0 +1,34 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import com.epam.jsdmx.infomodel.sdmx30.Component; +import com.epam.jsdmx.infomodel.sdmx30.ComponentList; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public final class DataStructureComponentsUtils { + + public static boolean isEmpty(ComponentList componentList) { + if (componentList == null) { + return true; + } + + List components = Optional.of(componentList) + .map(ComponentList::getComponents) + .orElse(Collections.emptyList()); + return components.isEmpty(); + } + + public static boolean areAllEmpty(ComponentList... componentLists) { + for (ComponentList componentList : componentLists) { + if (!isEmpty(componentList)) { + return false; + } + } + return true; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataStructureDefinitionWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataStructureDefinitionWriter.java new file mode 100644 index 0000000..05a712d --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataStructureDefinitionWriter.java @@ -0,0 +1,88 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinition; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptor; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; +import com.epam.jsdmx.serializer.common.TimeDimensionLocalRepresentationAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; + + +public class DataStructureDefinitionWriter extends MaintainableWriter { + + private final AttributeListWriter attributeWriter; + private final DimensionListWriter dimensionWriter; + private final GroupDimensionListWriter groupDimensionWriter; + private final MeasureListWriter measureWriter; + private final ReferenceAdapter referenceAdapter; + private final TimeDimensionLocalRepresentationAdapter dsdAdapter; + + + public DataStructureDefinitionWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + AttributeListWriter attributeWriter, + DimensionListWriter dimensionWriter, + GroupDimensionListWriter groupDimensionListWriter, + MeasureListWriter measureWriter, + ReferenceAdapter referenceAdapter, + TimeDimensionLocalRepresentationAdapter dsdAdapter) { + super(versionableWriter, linksWriter); + this.attributeWriter = attributeWriter; + this.dimensionWriter = dimensionWriter; + this.groupDimensionWriter = groupDimensionListWriter; + this.measureWriter = measureWriter; + this.referenceAdapter = referenceAdapter; + this.dsdAdapter = dsdAdapter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, DataStructureDefinition dsd) throws IOException { + super.writeFields(jsonGenerator, dsd); + writeDataStructureComponents(jsonGenerator, dsd); + writeMetadata(jsonGenerator, dsd.getMetadataStructure()); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getDataStructures(); + } + + @Override + protected String getArrayName() { + return StructureUtils.DATA_STRUCTURES; + } + + private void writeDataStructureComponents(JsonGenerator jsonGenerator, DataStructureDefinition dataStructureDefinition) throws IOException { + dataStructureDefinition = dsdAdapter.adapt(dataStructureDefinition); + AttributeDescriptor attributeDescriptor = dataStructureDefinition.getAttributeDescriptor(); + DimensionDescriptor dimensionDescriptor = dataStructureDefinition.getDimensionDescriptor(); + MeasureDescriptor measureDescriptor = dataStructureDefinition.getMeasureDescriptor(); + if (!DataStructureComponentsUtils.areAllEmpty( + attributeDescriptor, + dimensionDescriptor, + measureDescriptor + )) { + jsonGenerator.writeFieldName(StructureUtils.DATA_STRUCTURE_COMPONENTS); + jsonGenerator.writeStartObject(); + attributeWriter.write(jsonGenerator, attributeDescriptor); + dimensionWriter.write(jsonGenerator, dimensionDescriptor); + groupDimensionWriter.write(jsonGenerator, dataStructureDefinition.getGroupDimensionDescriptors()); + measureWriter.write(jsonGenerator, measureDescriptor); + jsonGenerator.writeEndObject(); + } + } + + private void writeMetadata(JsonGenerator jsonGenerator, ArtefactReference metadata) throws IOException { + if (metadata != null) { + jsonGenerator.writeStringField(StructureUtils.METADATA, referenceAdapter.toAdaptedUrn(metadata)); + } + } + +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataflowWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataflowWriter.java new file mode 100644 index 0000000..dd81e8b --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DataflowWriter.java @@ -0,0 +1,39 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Dataflow; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; + + +public class DataflowWriter extends MaintainableWriter { + + private final ReferenceAdapter referenceAdapter; + + public DataflowWriter(VersionableWriter versionableWriter, LinksWriter linksWriter, ReferenceAdapter referenceAdapter) { + super(versionableWriter, linksWriter); + this.referenceAdapter = referenceAdapter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, Dataflow dataflow) throws IOException { + super.writeFields(jsonGenerator, dataflow); + if (dataflow.getStructure() != null) { + jsonGenerator.writeStringField(StructureUtils.STRUCTURE, referenceAdapter.toAdaptedUrn(dataflow.getStructure())); + } + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getDataflows(); + } + + @Override + protected String getArrayName() { + return StructureUtils.DATAFLOWS; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DateTimeWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DateTimeWriter.java new file mode 100644 index 0000000..75306c5 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DateTimeWriter.java @@ -0,0 +1,78 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.AfterPeriod; +import com.epam.jsdmx.infomodel.sdmx30.BeforePeriod; +import com.epam.jsdmx.infomodel.sdmx30.RangePeriod; +import com.epam.jsdmx.infomodel.sdmx30.SelectionValue; +import com.epam.jsdmx.infomodel.sdmx30.TimeRangePeriod; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.tuple.Pair; + +public class DateTimeWriter { + public void writeValidDate(JsonGenerator jsonGenerator, + Instant instant, + String instantName) throws IOException { + if (instant != null) { + jsonGenerator.writeStringField( + instantName, + StructureUtils.mapInstantToString(instant) + ); + } + } + + public void writeTimeRanges(JsonGenerator jsonGenerator, List timeRanges) throws IOException { + if (CollectionUtils.isNotEmpty(timeRanges)) { + List> values = new ArrayList<>(); + for (SelectionValue timeRange : timeRanges) { + if (timeRange != null) { + if (timeRange instanceof AfterPeriod) { + AfterPeriod afterPeriod = (AfterPeriod) timeRange; + values.add(Pair.of(afterPeriod, StructureUtils.AFTER_PERIOD)); + } + if (timeRange instanceof BeforePeriod) { + BeforePeriod beforePeriod = (BeforePeriod) timeRange; + values.add(Pair.of(beforePeriod, StructureUtils.BEFORE_PERIOD)); + } + if (timeRange instanceof RangePeriod) { + RangePeriod rangePeriod = (RangePeriod) timeRange; + TimeRangePeriod startPeriod = rangePeriod.getStartPeriod(); + if (startPeriod != null) { + values.add(Pair.of(startPeriod, StructureUtils.START_PERIOD)); + } + TimeRangePeriod endPeriod = rangePeriod.getEndPeriod(); + if (endPeriod != null) { + values.add(Pair.of(endPeriod, StructureUtils.END_PERIOD)); + } + } + } + } + if (CollectionUtils.isNotEmpty(values)) { + jsonGenerator.writeFieldName(StructureUtils.TIME_RANGE); + jsonGenerator.writeStartObject(); + for (Pair value : values) { + writeTimeRangePeriod(jsonGenerator, value.getLeft(), value.getRight()); + } + jsonGenerator.writeEndObject(); + } + } + } + + public void writeTimeRangePeriod(JsonGenerator jsonGenerator, + TimeRangePeriod timeRangePeriod, + String timeRangePeriodName) throws IOException { + String period = timeRangePeriod.getPeriod(); + boolean inclusive = timeRangePeriod.isInclusive(); + jsonGenerator.writeFieldName(timeRangePeriodName); + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField(StructureUtils.PERIOD, period); + jsonGenerator.writeBooleanField(StructureUtils.IS_INCLUSIVE, inclusive); + jsonGenerator.writeEndObject(); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DimensionListWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DimensionListWriter.java new file mode 100644 index 0000000..7ed9e01 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/DimensionListWriter.java @@ -0,0 +1,92 @@ +package com.epam.jsdmx.json20.structure.writer; + + +import java.io.IOException; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.Dimension; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponent; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.TimeDimension; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = false) +public class DimensionListWriter extends IdentifiableWriter { + + private final ConceptRoleWriter conceptRoleWriter; + private final ComponentWriter componentWriter; + + public DimensionListWriter(AnnotableWriter annotableWriter, ConceptRoleWriter conceptRoleWriter, ComponentWriter componentWriter) { + super(annotableWriter); + this.conceptRoleWriter = conceptRoleWriter; + this.componentWriter = componentWriter; + } + + @Override + public void write(JsonGenerator jsonGenerator, IdentifiableArtefact identifiableArtefact) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.DIMENSION_LIST); + if (identifiableArtefact == null) { + jsonGenerator.writeNull(); + return; + } + DimensionDescriptorImpl dimensionDescriptor = (DimensionDescriptorImpl) identifiableArtefact; + dimensionDescriptor.setId(StructureUtils.DIMENSION_DESCRIPTOR_ID); + jsonGenerator.writeStartObject(); + super.write(jsonGenerator, dimensionDescriptor); + List components = dimensionDescriptor.getComponents(); + writeDimensions(jsonGenerator, components); + writeTimeDimensions(jsonGenerator, components); + + jsonGenerator.writeEndObject(); + } + + private void writeTimeDimensions(JsonGenerator jsonGenerator, List components) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.TIME_DIMENSIONS); + jsonGenerator.writeStartArray(); + List timeDimensions = Optional.ofNullable(components) + .stream() + .flatMap(List::stream) + .filter(d -> TimeDimension.class.isAssignableFrom(d.getClass())) + .map(TimeDimension.class::cast) + .collect(Collectors.toList()); + if (!timeDimensions.isEmpty()) { + for (TimeDimension dimension : timeDimensions) { + jsonGenerator.writeStartObject(); + componentWriter.write(jsonGenerator, dimension); + jsonGenerator.writeNumberField(StructureUtils.POSITION, dimension.getOrder()); + jsonGenerator.writeStringField(StructureUtils.TYPE, dimension.getStructureClass() + .toString()); + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + + private void writeDimensions(JsonGenerator jsonGenerator, List components) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.DIMENSIONS); + jsonGenerator.writeStartArray(); + List dimensions = Optional.ofNullable(components) + .stream() + .flatMap(List::stream) + .filter(d -> Dimension.class.isAssignableFrom(d.getClass())) + .map(Dimension.class::cast) + .collect(Collectors.toList()); + if (!dimensions.isEmpty()) { + for (Dimension dimension : dimensions) { + jsonGenerator.writeStartObject(); + componentWriter.write(jsonGenerator, dimension); + jsonGenerator.writeNumberField(StructureUtils.POSITION, dimension.getOrder()); + jsonGenerator.writeStringField(StructureUtils.TYPE, dimension.getStructureClass().toString()); + conceptRoleWriter.write(jsonGenerator, dimension.getConceptRoles()); + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GeoFeatureSetCodeWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GeoFeatureSetCodeWriter.java new file mode 100644 index 0000000..7b07006 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GeoFeatureSetCodeWriter.java @@ -0,0 +1,19 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCode; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class GeoFeatureSetCodeWriter extends CodeWriter { + + @Override + public void writeFields(JsonGenerator jsonGenerator, + GeoFeatureSetCode code, + NameableWriter nameableWriter) throws IOException { + super.writeFields(jsonGenerator, code, nameableWriter); + String value = code.getValue(); + jsonGenerator.writeStringField(StructureUtils.VALUE, value); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GeoGridCodelistWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GeoGridCodelistWriter.java new file mode 100644 index 0000000..0f14993 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GeoGridCodelistWriter.java @@ -0,0 +1,52 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.GeoGridCodelist; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class GeoGridCodelistWriter extends MaintainableWriter { + + private final CodelistExtensionWriter codelistExtensionWriter; + private final GridCodeWriter gridCodeWriter; + private final NameableWriter nameableWriter; + + public GeoGridCodelistWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + CodelistExtensionWriter codelistExtensionWriter, + GridCodeWriter gridCodeWriter, + NameableWriter nameableWriter) { + super(versionableWriter, linksWriter); + this.codelistExtensionWriter = codelistExtensionWriter; + this.gridCodeWriter = gridCodeWriter; + this.nameableWriter = nameableWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, GeoGridCodelist geoGridCodelist) throws IOException { + super.writeFields(jsonGenerator, geoGridCodelist); + + jsonGenerator.writeBooleanField(StructureUtils.IS_PARTIAL, geoGridCodelist.isPartial()); + jsonGenerator.writeStringField(StructureUtils.GEO_TYPE, StructureUtils.GEO_GRID_CODELIST); + if (geoGridCodelist.getGridDefinition() != null) { + jsonGenerator.writeStringField(StructureUtils.GRID_DEFINITION, geoGridCodelist.getGridDefinition()); + } + + gridCodeWriter.writeCodes(jsonGenerator, geoGridCodelist.getItems(), StructureUtils.GEO_GRID_CODES, nameableWriter); + + codelistExtensionWriter.writeCodeListExtentions(jsonGenerator, geoGridCodelist.getExtensions()); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getGeoGridCodelists(); + } + + @Override + protected String getArrayName() { + return StructureUtils.GEO_GRID_CODELISTS; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GeographicCodelistWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GeographicCodelistWriter.java new file mode 100644 index 0000000..7e20e7b --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GeographicCodelistWriter.java @@ -0,0 +1,58 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.GeographicCodelist; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class GeographicCodelistWriter extends MaintainableWriter { + + private final GeoFeatureSetCodeWriter codeWriter; + private final CodelistExtensionWriter codelistExtensionWriter; + private final NameableWriter nameableWriter; + + public GeographicCodelistWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + GeoFeatureSetCodeWriter codeWriter, + CodelistExtensionWriter codelistExtensionWriter, + NameableWriter nameableWriter) { + super(versionableWriter, linksWriter); + this.codeWriter = codeWriter; + this.codelistExtensionWriter = codelistExtensionWriter; + this.nameableWriter = nameableWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, GeographicCodelist geographicCodelist) throws IOException { + super.writeFields(jsonGenerator, geographicCodelist); + + jsonGenerator.writeBooleanField(StructureUtils.IS_PARTIAL, geographicCodelist.isPartial()); + jsonGenerator.writeStringField(StructureUtils.GEO_TYPE, StructureUtils.GEOGRAPHIC_CODELIST); + + writeGeoFeatureCodelists(jsonGenerator, geographicCodelist); + + codelistExtensionWriter.writeCodeListExtentions(jsonGenerator, geographicCodelist.getExtensions()); + } + + private void writeGeoFeatureCodelists(JsonGenerator jsonGenerator, GeographicCodelist geographicCodelist) throws IOException { + codeWriter.writeCodes( + jsonGenerator, + geographicCodelist.getItems(), + StructureUtils.GEO_FEATURE_SET_CODES, + nameableWriter + ); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getGeographicCodelists(); + } + + @Override + protected String getArrayName() { + return StructureUtils.GEOGRAPHIC_CODELISTS; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GridCodeWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GridCodeWriter.java new file mode 100644 index 0000000..719fe2f --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GridCodeWriter.java @@ -0,0 +1,18 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.GridCode; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class GridCodeWriter extends CodeWriter { + + @Override + public void writeFields(JsonGenerator jsonGenerator, GridCode code, NameableWriter nameableWriter) throws IOException { + super.writeFields(jsonGenerator, code, nameableWriter); + if (code.getGeoCell() != null) { + jsonGenerator.writeStringField(StructureUtils.GEO_CELL, code.getGeoCell()); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GroupDimensionListWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GroupDimensionListWriter.java new file mode 100644 index 0000000..a0d20c2 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/GroupDimensionListWriter.java @@ -0,0 +1,40 @@ +package com.epam.jsdmx.json20.structure.writer; + + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.GroupDimensionDescriptor; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections4.CollectionUtils; + +public class GroupDimensionListWriter { + + private final IdentifiableWriter identifiableWriter; + + public GroupDimensionListWriter(IdentifiableWriter identifiableWriter) { + this.identifiableWriter = identifiableWriter; + } + + public void write(JsonGenerator jsonGenerator, List descriptors) throws IOException { + if (CollectionUtils.isEmpty(descriptors)) { + return; + } + + jsonGenerator.writeArrayFieldStart(StructureUtils.GROUPS); + + for (GroupDimensionDescriptor descriptor : descriptors) { + jsonGenerator.writeStartObject(); + identifiableWriter.write(jsonGenerator, descriptor); + + jsonGenerator.writeFieldName(StructureUtils.GROUP_DIMENSIONS); + String[] dimensionsStringList = descriptor.getDimensions().toArray(new String[0]); + jsonGenerator.writeArray(dimensionsStringList, 0, dimensionsStringList.length); + + jsonGenerator.writeEndObject(); + } + + jsonGenerator.writeEndArray(); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/HierarchyAssociationWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/HierarchyAssociationWriter.java new file mode 100644 index 0000000..9348674 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/HierarchyAssociationWriter.java @@ -0,0 +1,48 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyAssociation; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class HierarchyAssociationWriter extends MaintainableWriter { + + public HierarchyAssociationWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter) { + super(versionableWriter, linksWriter); + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, HierarchyAssociation hierarchyAssociation) throws IOException { + super.writeFields(jsonGenerator, hierarchyAssociation); + + ArtefactReference contextObject = hierarchyAssociation.getContextObject(); + if (contextObject != null) { + jsonGenerator.writeStringField(StructureUtils.CONTEXT_OBJECT, contextObject.getUrn()); + } + + ArtefactReference linkedHierarchy = hierarchyAssociation.getLinkedHierarchy(); + if (linkedHierarchy != null) { + jsonGenerator.writeStringField(StructureUtils.LINKED_HIERARCHY, linkedHierarchy.getUrn()); + } + + ArtefactReference linkedObject = hierarchyAssociation.getLinkedObject(); + if (linkedObject != null) { + jsonGenerator.writeStringField(StructureUtils.LINKED_OBJECT, linkedObject.getUrn()); + } + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getHierarchyAssociations(); + } + + @Override + protected String getArrayName() { + return StructureUtils.HIERARCHY_ASSOCIATIONS; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/HierarchyWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/HierarchyWriter.java new file mode 100644 index 0000000..da3e46f --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/HierarchyWriter.java @@ -0,0 +1,110 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CodingFormat; +import com.epam.jsdmx.infomodel.sdmx30.Facet; +import com.epam.jsdmx.infomodel.sdmx30.HierarchicalCode; +import com.epam.jsdmx.infomodel.sdmx30.Hierarchy; +import com.epam.jsdmx.infomodel.sdmx30.Level; +import com.epam.jsdmx.infomodel.sdmx30.TextFormatImpl; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class HierarchyWriter extends MaintainableWriter { + + private final IdentifiableWriter identifiableWriter; + private final NameableWriter nameableWriter; + private final ReferenceAdapter referenceAdapter; + + public HierarchyWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + IdentifiableWriter identifiableWriter, + NameableWriter nameableWriter, + ReferenceAdapter referenceAdapter) { + super(versionableWriter, linksWriter); + this.identifiableWriter = identifiableWriter; + this.nameableWriter = nameableWriter; + this.referenceAdapter = referenceAdapter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, Hierarchy hierarchy) throws IOException { + super.writeFields(jsonGenerator, hierarchy); + jsonGenerator.writeBooleanField(StructureUtils.HAS_FORMAT_LEVELS, hierarchy.isHasFormalLevels()); + writeHierarchyCodes(jsonGenerator, hierarchy.getCodes()); + writeHierarchyLevel(jsonGenerator, hierarchy.getLevel()); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getHierarchies(); + } + + @Override + protected String getArrayName() { + return StructureUtils.HIERARCHIES; + } + + private void writeHierarchyLevel(JsonGenerator jsonGenerator, Level level) throws IOException { + if (level != null) { + jsonGenerator.writeFieldName(StructureUtils.LEVEL); + jsonGenerator.writeStartObject(); + nameableWriter.write(jsonGenerator, level); + writeCodingFormat(jsonGenerator, level); + writeHierarchyLevel(jsonGenerator, level.getChild()); + jsonGenerator.writeEndObject(); + } + + } + + private void writeCodingFormat(JsonGenerator jsonGenerator, Level level) throws IOException { + List levelCodeFormat = level.getCodeFormat(); + if (levelCodeFormat != null) { + jsonGenerator.writeFieldName(StructureUtils.CODING_FORMAT); + jsonGenerator.writeStartObject(); + for (CodingFormat codingFormat : levelCodeFormat) { + if (codingFormat != null) { + Facet format = codingFormat.getCodingFormat(); + TextFormatImpl textFormat = new TextFormatImpl(Set.of(format)); + StructureUtils.writeCommonFormatAttributes(jsonGenerator, textFormat); + } + } + jsonGenerator.writeEndObject(); + } + } + + private void writeHierarchyCodes(JsonGenerator jsonGenerator, List codes) throws IOException { + if (codes != null) { + jsonGenerator.writeFieldName(StructureUtils.HIERARCHICAL_CODES); + jsonGenerator.writeStartArray(); + if (!codes.isEmpty()) { + for (HierarchicalCode code : codes) { + jsonGenerator.writeStartObject(); + identifiableWriter.write(jsonGenerator, code); + if (code.getValidFrom() != null) { + jsonGenerator.writeStringField(StructureUtils.VALID_FROM, StructureUtils.mapInstantToString(code.getValidFrom())); + } + if (code.getValidTo() != null) { + jsonGenerator.writeStringField(StructureUtils.VALID_TO, StructureUtils.mapInstantToString(code.getValidTo())); + } + if (code.getCode() != null) { + jsonGenerator.writeStringField(StructureUtils.CODE, referenceAdapter.toAdaptedUrn(code.getCode())); + } + if (code.getLevelId() != null) { + jsonGenerator.writeStringField(StructureUtils.LEVEL, code.getLevelId()); + } + if (code.getHierarchicalCodes() != null && !code.getHierarchicalCodes().isEmpty()) { + writeHierarchyCodes(jsonGenerator, code.getHierarchicalCodes()); + } + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/IdentifiableWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/IdentifiableWriter.java new file mode 100644 index 0000000..7609eb5 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/IdentifiableWriter.java @@ -0,0 +1,26 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefact; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.Data; + +@Data +public class IdentifiableWriter { + + private AnnotableWriter annotableWriter; + + public IdentifiableWriter(AnnotableWriter annotableWriter) { + this.annotableWriter = annotableWriter; + } + + public void write(JsonGenerator jsonGenerator, IdentifiableArtefact artefact) throws IOException { + annotableWriter.write(jsonGenerator, artefact); + String id = artefact.getId(); + if (id != null) { + jsonGenerator.writeStringField(StructureUtils.ID, id); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ItemMapWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ItemMapWriter.java new file mode 100644 index 0000000..89d3834 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ItemMapWriter.java @@ -0,0 +1,95 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.time.Instant; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections.CollectionUtils; + +public class ItemMapWriter { + + private final ReferenceAdapter referenceAdapter; + + protected ItemMapWriter(ReferenceAdapter referenceAdapter) { + this.referenceAdapter = referenceAdapter; + } + + protected void writeItemMaps(JsonGenerator jsonGenerator, + List itemMaps, + AnnotableWriter annotableWriter) throws IOException { + if (CollectionUtils.isNotEmpty(itemMaps)) { + jsonGenerator.writeFieldName(StructureUtils.ITEM_MAPS); + jsonGenerator.writeStartArray(); + for (ItemMap itemMap : itemMaps) { + if (itemMap != null) { + + jsonGenerator.writeStartObject(); + + annotableWriter.write(jsonGenerator, itemMap); + + String source = itemMap.getSource(); + writeSource(jsonGenerator, source); + + String target = itemMap.getTarget(); + writeTarget(jsonGenerator, target); + + Instant validFrom = itemMap.getValidFrom(); + writeValidFrom(jsonGenerator, validFrom); + + Instant validTo = itemMap.getValidTo(); + writeValidTo(jsonGenerator, validTo); + + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } + + protected void writeSource(JsonGenerator jsonGenerator, ArtefactReference source) throws IOException { + if (source != null) { + jsonGenerator.writeStringField(StructureUtils.SOURCE, referenceAdapter.toAdaptedUrn(source)); + } + } + + private void writeSource(JsonGenerator jsonGenerator, String source) throws IOException { + if (source != null) { + jsonGenerator.writeStringField(StructureUtils.SOURCE_VALUE, source); + } + } + + protected void writeTarget(JsonGenerator jsonGenerator, ArtefactReference target) throws IOException { + if (target != null) { + jsonGenerator.writeStringField(StructureUtils.TARGET, referenceAdapter.toAdaptedUrn(target)); + } + } + + private void writeTarget(JsonGenerator jsonGenerator, String target) throws IOException { + if (target != null) { + jsonGenerator.writeStringField(StructureUtils.TARGET_VALUE, target); + } + } + + private void writeValidTo(JsonGenerator jsonGenerator, Instant validTo) throws IOException { + if (validTo != null) { + jsonGenerator.writeStringField( + StructureUtils.VALID_TO, + StructureUtils.mapInstantToString(validTo) + ); + } + } + + private void writeValidFrom(JsonGenerator jsonGenerator, Instant validFrom) throws IOException { + if (validFrom != null) { + jsonGenerator.writeStringField( + StructureUtils.VALID_FROM, + StructureUtils.mapInstantToString(validFrom) + ); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/JsonStructureWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/JsonStructureWriter.java new file mode 100644 index 0000000..d36c778 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/JsonStructureWriter.java @@ -0,0 +1,137 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.ref.WeakReference; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.json20.structure.reader.JsonRuntimeException; +import com.epam.jsdmx.serializer.sdmx30.structure.StructureWriter; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Streaming serialization for json (2.0) + */ +public class JsonStructureWriter extends BaseWriterJson implements StructureWriter { + + protected final MetaWriter metaWriter; + protected final List> writers; + private static final String LAZY = "Lazy"; + + public JsonStructureWriter(ObjectMapper mapper, + OutputStream outputStream, + MetaWriter metaWriter, + List> writers) { + super(mapper, outputStream); + this.metaWriter = metaWriter; + this.writers = writers; + } + + @Override + public void write(Artefacts artefacts) { + try { + if (artefacts != null) { + jsonGenerator.writeStartObject(); + jsonGenerator.writeFieldName(StructureUtils.DATA); + + jsonGenerator.writeStartObject(); + writeArtefacts(artefacts); + jsonGenerator.writeEndObject(); + + metaWriter.writeDefaultHeader(jsonGenerator); + + writeCustomSection(artefacts, jsonGenerator); + + jsonGenerator.writeEndObject(); + + jsonGenerator.flush(); + jsonGenerator.close(); + } + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + protected void writeCustomSection(Artefacts artefacts, JsonGenerator jsonGenerator) { + // do nothing here + } + + protected void writeArtefacts(Artefacts artefacts) throws IOException { + + writers.forEach(writer -> { + Set maintainableArtefacts = writer.extractArtefacts(artefacts); + maintainableArtefacts = isLazy(maintainableArtefacts) ? maintainableArtefacts : new HashSet<>(maintainableArtefacts); + try { + if (!maintainableArtefacts.isEmpty()) { + jsonGenerator.writeFieldName(writer.getArrayName()); + jsonGenerator.writeStartArray(); + + // Use an iterator to remove artefacts from the set after writing + Iterator iterator = maintainableArtefacts.iterator(); + + while (iterator.hasNext()) { + MaintainableArtefact artefact = iterator.next(); + + try { + // This will ensure that the objects are automatically collected as soon as no strong references exist + WeakReference weakRef = new WeakReference<>(artefact); + writer.write(jsonGenerator, weakRef.get()); + + // Remove the artefact from the set to allow garbage collection + iterator.remove(); + + // Remove the strong reference + artefact = null; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + jsonGenerator.writeEndArray(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + + protected void writeArtefact(MaintainableWriter writer, + Set artefacts, + String artefactName) throws IOException { + if (artefacts != null && !artefacts.isEmpty()) { + jsonGenerator.writeFieldName(artefactName); + jsonGenerator.writeStartArray(); + + Set maintainableArtefacts = isLazy(artefacts) ? artefacts : new HashSet<>(artefacts); + + Iterator iterator = maintainableArtefacts.iterator(); + + while (iterator.hasNext()) { + T artefact = iterator.next(); + + // This will ensure that the objects are automatically collected as soon as no strong references exist + WeakReference weakRef = new WeakReference<>(artefact); + writer.write(jsonGenerator, weakRef.get()); + + // Remove the artefact from the collection to make it eligible for GC + iterator.remove(); + + // Remove the strong reference + artefact = null; + } + + jsonGenerator.writeEndArray(); + } + } + + private boolean isLazy(Set artefacts) { + return artefacts.getClass().getName().contains(LAZY); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/JsonWriterFactory.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/JsonWriterFactory.java new file mode 100644 index 0000000..a86c8d8 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/JsonWriterFactory.java @@ -0,0 +1,378 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Locale.LanguageRange; +import java.util.Map; + +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; +import com.epam.jsdmx.serializer.common.StubDataStructureLocalRepresentationAdapter; +import com.epam.jsdmx.serializer.common.TimeDimensionLocalRepresentationAdapter; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultHeaderProvider; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultReferenceAdapter; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public final class JsonWriterFactory { + + private final ObjectMapper mapper; + private final List languagePriorities; + private final ReferenceAdapter referenceAdapter; + private final TimeDimensionLocalRepresentationAdapter dsdAdapter; + + private JsonWriterFactory() { + this(new ObjectMapper(), List.of(), new DefaultReferenceAdapter(), new StubDataStructureLocalRepresentationAdapter()); + } + + public JsonWriterFactory(ObjectMapper mapper, + List languagePriorities, + TimeDimensionLocalRepresentationAdapter timeDimensionLocalRepresentationAdapter) { + this(mapper, languagePriorities, new DefaultReferenceAdapter(), timeDimensionLocalRepresentationAdapter); + } + + public JsonWriterFactory(ObjectMapper mapper, + List languagePriorities, + ReferenceAdapter referenceAdapter, + TimeDimensionLocalRepresentationAdapter timeDimensionLocalRepresentationAdapter) { + this.mapper = mapper; + this.languagePriorities = languagePriorities; + this.referenceAdapter = referenceAdapter; + this.dsdAdapter = timeDimensionLocalRepresentationAdapter; + } + + public JsonStructureWriter newInstance(OutputStream outputStream) { + final var metaWriter = new MetaWriter(languagePriorities, new DefaultHeaderProvider()); + final var structureWriters = writers(); + + return new JsonStructureWriter( + mapper, + outputStream, + metaWriter, + structureWriters + ); + } + + public JsonStructureWriter newInstance(OutputStream outputStream, + Map> customStructureWriters) { + final var metaWriter = new MetaWriter(languagePriorities, new DefaultHeaderProvider()); + final var defaultStructureWriters = writers(); + final List> structureWriters = new ArrayList<>(); + + for (var writer : defaultStructureWriters) { + writer.getWritableArtefactStructureClass() + .filter(customStructureWriters::containsKey) + .map(customStructureWriters::get) + .ifPresentOrElse(structureWriters::add, () -> structureWriters.add(writer)); + } + + return new JsonStructureWriter( + mapper, + outputStream, + metaWriter, + structureWriters + ); + } + + private ReferenceAdapter getUrnAdapter() { + return referenceAdapter; + } + + private TimeDimensionLocalRepresentationAdapter getDsdAdapter() { + return dsdAdapter; + } + + private RepresentationWriter getRepresentationWriter() { + return new RepresentationWriter(getUrnAdapter()); + } + + private LinksWriter getLinksWriter() { + return new LinksWriter(getUrnAdapter()); + } + + private AnnotableWriter getAnnotableWriter() { + return new AnnotableWriter(getLinksWriter()); + } + + private IdentifiableWriter getIdentifiableWriter() { + return new IdentifiableWriter(getAnnotableWriter()); + } + + private NameableWriter getNameableWriter() { + return new NameableWriter(getIdentifiableWriter()); + } + + private VersionableWriter getVersionableWriter() { + return new VersionableWriter(getNameableWriter()); + } + + private ComponentWriter getComponentWriter() { + return new ComponentWriter(getIdentifiableWriter(), getRepresentationWriter(), getUrnAdapter()); + } + + private ConceptRoleWriter getConceptRoleWriter() { + return new ConceptRoleWriter(getUrnAdapter()); + } + + private DateTimeWriter getDateTimeWriter() { + return new DateTimeWriter(); + } + + private DataKeySetsWriter getDataKeySetsWriter() { + return new DataKeySetsWriter(getAnnotableWriter(), getMemberSelectionWriter(), getDateTimeWriter()); + } + + private AttributeListWriter getAttributeListWriter() { + return new AttributeListWriter(getAnnotableWriter(), getConceptRoleWriter(), getComponentWriter()); + } + + private DimensionListWriter getDimensionListWriter() { + return new DimensionListWriter(getAnnotableWriter(), getConceptRoleWriter(), getComponentWriter()); + } + + private GroupDimensionListWriter getGroupDimensionListWriter() { + return new GroupDimensionListWriter(getIdentifiableWriter()); + } + + private MeasureListWriter getMeasureListWriter() { + return new MeasureListWriter(getAnnotableWriter(), getConceptRoleWriter(), getComponentWriter()); + } + + private CodeWriterImpl getCodeImplWriter() { + return new CodeWriterImpl(); + } + + private GeoFeatureSetCodeWriter getGeoFeatureSetCodeWriter() { + return new GeoFeatureSetCodeWriter(); + } + + private GridCodeWriter getGridCodeWriter() { + return new GridCodeWriter(); + } + + private CodelistExtensionWriter getCodelistExtensionWriter() { + return new CodelistExtensionWriter(getUrnAdapter()); + } + + private CubeRegionWriter getCubeRegionWriter() { + return new CubeRegionWriter(getMemberSelectionWriter(), getDateTimeWriter(), getAnnotableWriter()); + } + + private ContactsWriter getContactsWriter() { + return new ContactsWriter(); + } + + private OrganisationWriter getOrganisationWriter() { + return new OrganisationWriter(getContactsWriter(), getNameableWriter()); + } + + private MemberSelectionWriter getMemberSelectionWriter() { + return new MemberSelectionWriter(getDateTimeWriter()); + } + + private AgencySchemeWriter getAgencySchemeWriter() { + return new AgencySchemeWriter(getVersionableWriter(), getLinksWriter(), getOrganisationWriter()); + } + + private CategorisationWriter getCategorisationWriter() { + return new CategorisationWriter(getVersionableWriter(), getLinksWriter(), getUrnAdapter()); + } + + private ItemMapWriter getItemMapWriter() { + return new ItemMapWriter(getUrnAdapter()); + } + + private CategorySchemeMapWriter getCategorySchemeMapWriter() { + return new CategorySchemeMapWriter(getVersionableWriter(), getLinksWriter(), getAnnotableWriter(), getItemMapWriter()); + } + + private CategorySchemeWriter getCategorySchemeWriter() { + return new CategorySchemeWriter(getVersionableWriter(), getLinksWriter(), getNameableWriter()); + } + + private CodelistWriter getCodelistWriter() { + return new CodelistWriter(getVersionableWriter(), getLinksWriter(), getCodeImplWriter(), getCodelistExtensionWriter(), getNameableWriter()); + } + + private ConceptSchemeMapWriter getConceptSchemeMapWriter() { + return new ConceptSchemeMapWriter(getVersionableWriter(), getLinksWriter(), getAnnotableWriter(), getItemMapWriter()); + } + + private ConceptSchemeWriter getConceptSchemeWriter() { + return new ConceptSchemeWriter(getVersionableWriter(), getLinksWriter(), getNameableWriter(), getRepresentationWriter()); + } + + private DataConstraintWriter getDataConstraintWriter() { + return new DataConstraintWriter(getVersionableWriter(), getLinksWriter(), getCubeRegionWriter(), getDataKeySetsWriter(), getUrnAdapter()); + } + + private DataConsumerSchemeWriter getDataConsumerSchemeWriter() { + return new DataConsumerSchemeWriter(getVersionableWriter(), getLinksWriter(), getOrganisationWriter()); + } + + private DataflowWriter getDataflowWriter() { + return new DataflowWriter(getVersionableWriter(), getLinksWriter(), getUrnAdapter()); + } + + private DataProviderSchemeWriter getDataProviderSchemeWriter() { + return new DataProviderSchemeWriter(getVersionableWriter(), getLinksWriter(), getOrganisationWriter()); + } + + private DataStructureDefinitionWriter getDataStructureDefinitionWriter() { + return new DataStructureDefinitionWriter( + getVersionableWriter(), + getLinksWriter(), + getAttributeListWriter(), + getDimensionListWriter(), + getGroupDimensionListWriter(), + getMeasureListWriter(), + getUrnAdapter(), + getDsdAdapter() + ); + } + + private HierarchyAssociationWriter getHierarchyAssociationWriter() { + return new HierarchyAssociationWriter(getVersionableWriter(), getLinksWriter()); + } + + private HierarchyWriter getHierarchyWriter() { + return new HierarchyWriter(getVersionableWriter(), getLinksWriter(), getIdentifiableWriter(), getNameableWriter(), getUrnAdapter()); + } + + private MetadataConstraintWriter getMetadataConstraintWriter() { + return new MetadataConstraintWriter(getVersionableWriter(), getLinksWriter(), getMemberSelectionWriter(), getUrnAdapter()); + } + + private MetadataflowWriter getMetadataflowWriter() { + return new MetadataflowWriter(getVersionableWriter(), getLinksWriter(), getUrnAdapter()); + } + + private MetadataProviderSchemeWriter getMetadataProviderSchemeWriter() { + return new MetadataProviderSchemeWriter(getVersionableWriter(), getLinksWriter(), getOrganisationWriter()); + } + + private MetadataProvisionAgreementWriter getMetadataProvisionAgreementWriter() { + return new MetadataProvisionAgreementWriter(getVersionableWriter(), getLinksWriter(), getUrnAdapter()); + } + + private MetadataStructureDefinitionWriter getMetadataStructureDefinitionWriter() { + return new MetadataStructureDefinitionWriter( + getVersionableWriter(), + getLinksWriter(), + getComponentWriter(), + getIdentifiableWriter() + ); + } + + private OrganisationSchemeMapWriter getOrganisationSchemeMapWriter() { + return new OrganisationSchemeMapWriter(getVersionableWriter(), getLinksWriter(), getAnnotableWriter(), getItemMapWriter()); + } + + private OrganisationUnitSchemeWriter getOrganisationUnitSchemeWriter() { + return new OrganisationUnitSchemeWriter(getVersionableWriter(), getLinksWriter(), getOrganisationWriter()); + } + + private ProcessWriter getProcessWriter() { + return new ProcessWriter( + getVersionableWriter(), + getLinksWriter(), + getNameableWriter(), + getAnnotableWriter(), + getIdentifiableWriter() + ); + } + + private ProvisionAgreementWriter getProvisionAgreementWriter() { + return new ProvisionAgreementWriter(getVersionableWriter(), getLinksWriter(), getUrnAdapter()); + } + + private ReportingTaxonomyWriter getReportingTaxonomyWriter() { + return new ReportingTaxonomyWriter(getVersionableWriter(), getLinksWriter(), getNameableWriter(), getUrnAdapter()); + } + + private ReportingTaxonomyMapWriter getReportingTaxonomyMapWriter() { + return new ReportingTaxonomyMapWriter(getVersionableWriter(), getLinksWriter(), getAnnotableWriter(), getItemMapWriter()); + } + + private RepresentationMapWriter getRepresentationMapWriter() { + return new RepresentationMapWriter(getVersionableWriter(), getLinksWriter(), getAnnotableWriter(), getUrnAdapter()); + } + + private StructureMapWriter getStructureMapWriter() { + return new StructureMapWriter( + getVersionableWriter(), + getLinksWriter(), + getAnnotableWriter(), + getIdentifiableWriter(), + getUrnAdapter() + ); + } + + private ValueListWriter getValueListWriter() { + return new ValueListWriter( + getVersionableWriter(), + getLinksWriter(), + getAnnotableWriter() + ); + } + + private GeographicCodelistWriter getGeographicCodelistWriter() { + return new GeographicCodelistWriter( + getVersionableWriter(), + getLinksWriter(), + getGeoFeatureSetCodeWriter(), + getCodelistExtensionWriter(), + getNameableWriter() + ); + } + + private GeoGridCodelistWriter getGeoGridCodelistWriter() { + return new GeoGridCodelistWriter( + getVersionableWriter(), + getLinksWriter(), + getCodelistExtensionWriter(), + getGridCodeWriter(), + getNameableWriter() + ); + } + + private List> writers() { + return List.of( + getAgencySchemeWriter(), + getCategorisationWriter(), + getCategorySchemeWriter(), + getCategorySchemeMapWriter(), + getCodelistWriter(), + getConceptSchemeWriter(), + getConceptSchemeMapWriter(), + getDataConstraintWriter(), + getDataConsumerSchemeWriter(), + getDataProviderSchemeWriter(), + getDataStructureDefinitionWriter(), + getDataflowWriter(), + getHierarchyWriter(), + getHierarchyAssociationWriter(), + getMetadataConstraintWriter(), + getMetadataProviderSchemeWriter(), + getMetadataProvisionAgreementWriter(), + getMetadataStructureDefinitionWriter(), + getMetadataflowWriter(), + getOrganisationSchemeMapWriter(), + getOrganisationUnitSchemeWriter(), + getProcessWriter(), + getProvisionAgreementWriter(), + getReportingTaxonomyWriter(), + getReportingTaxonomyMapWriter(), + getRepresentationMapWriter(), + getStructureMapWriter(), + getValueListWriter(), + getGeographicCodelistWriter(), + getGeoGridCodelistWriter() + ); + } + + +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/LinksWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/LinksWriter.java new file mode 100644 index 0000000..12124ba --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/LinksWriter.java @@ -0,0 +1,34 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalUri; +import com.epam.jsdmx.infomodel.sdmx30.Link; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class LinksWriter { + + private final ReferenceAdapter referenceAdapter; + + public LinksWriter(ReferenceAdapter referenceAdapter) { + this.referenceAdapter = referenceAdapter; + } + + public void writeLinks(JsonGenerator jsonGenerator, List links) throws IOException { + // Don't write links for sdmx 3.0 artefacts + } + + public void writeLinks(JsonGenerator jsonGenerator, InternationalUri uri) throws IOException { + if (uri != null) { + jsonGenerator.writeFieldName(StructureUtils.LINKS); + jsonGenerator.writeStartArray(); + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField(StructureUtils.URI, uri.getForDefaultLocale().toString()); + jsonGenerator.writeEndObject(); + jsonGenerator.writeEndArray(); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MaintainableWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MaintainableWriter.java new file mode 100644 index 0000000..aa095b3 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MaintainableWriter.java @@ -0,0 +1,60 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; +import com.epam.jsdmx.json20.structure.reader.JsonRuntimeException; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RequiredArgsConstructor +public abstract class MaintainableWriter { + + private final VersionableWriter versionableWriter; + private final LinksWriter linksWriter; + + public void write(JsonGenerator jsonGenerator, MaintainableArtefact artefact) throws IOException { + jsonGenerator.writeStartObject(); + writeFields(jsonGenerator, (T) artefact); + jsonGenerator.writeEndObject(); + } + + protected void writeFields(JsonGenerator jsonGenerator, T artefact) throws IOException { + linksWriter.writeLinks(jsonGenerator, artefact.getLinks()); + versionableWriter.write(jsonGenerator, artefact); + if (artefact.getOrganizationId() != null) { + jsonGenerator.writeStringField(StructureUtils.AGENCY_ID, artefact.getOrganizationId()); + } + } + + public void writeAndClose(JsonGenerator jsonGenerator, T maintainableArtefact) { + try (jsonGenerator) { + write(jsonGenerator, maintainableArtefact); + } catch (IOException e) { + throw new JsonRuntimeException(e); + } + } + + public Optional getWritableArtefactStructureClass() { + // if there is a need to find writer by its maintainable artefact type + return Optional.empty(); + } + + protected Set extractArtefacts(Artefacts artefacts) { + //different for writers with stream and the ones with dto + return Collections.emptySet(); + } + + protected String getArrayName() { + //different for writers with stream and the ones with dto + return null; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MappedComponent.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MappedComponent.java new file mode 100644 index 0000000..9ce0bd8 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MappedComponent.java @@ -0,0 +1,13 @@ +package com.epam.jsdmx.json20.structure.writer; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MappedComponent { + private String source; + private String target; +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MeasureListWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MeasureListWriter.java new file mode 100644 index 0000000..afdc85b --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MeasureListWriter.java @@ -0,0 +1,59 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.Measure; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptorImpl; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.EqualsAndHashCode; +import org.apache.commons.collections.CollectionUtils; + +@EqualsAndHashCode(callSuper = false) +public class MeasureListWriter extends IdentifiableWriter { + + private final ConceptRoleWriter conceptRoleWriter; + + private final ComponentWriter componentWriter; + + public MeasureListWriter(AnnotableWriter annotableWriter, ConceptRoleWriter conceptRoleWriter, ComponentWriter componentWriter) { + super(annotableWriter); + this.conceptRoleWriter = conceptRoleWriter; + this.componentWriter = componentWriter; + } + + @Override + public void write(JsonGenerator jsonGenerator, IdentifiableArtefact identifiableArtefact) throws IOException { + if (identifiableArtefact == null) { + return; + } + + jsonGenerator.writeFieldName(StructureUtils.MEASURE_LIST); + MeasureDescriptorImpl measureDescriptor = (MeasureDescriptorImpl) identifiableArtefact; + measureDescriptor.setId(StructureUtils.MEASURE_DESCRIPTOR_ID); + jsonGenerator.writeStartObject(); + super.write(jsonGenerator, measureDescriptor); + List components = measureDescriptor.getComponents(); + writeMeasures(jsonGenerator, components); + jsonGenerator.writeEndObject(); + } + + private void writeMeasures(JsonGenerator jsonGenerator, List components) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.MEASURES); + jsonGenerator.writeStartArray(); + if (CollectionUtils.isNotEmpty(components)) { + for (Measure measure : components) { + if (measure != null) { + jsonGenerator.writeStartObject(); + componentWriter.write(jsonGenerator, measure); + jsonGenerator.writeBooleanField(StructureUtils.IS_MANDATORY, measure.getMinOccurs() > 0); + conceptRoleWriter.write(jsonGenerator, measure.getConceptRoles()); + jsonGenerator.writeEndObject(); + } + } + } + jsonGenerator.writeEndArray(); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MemberSelectionWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MemberSelectionWriter.java new file mode 100644 index 0000000..e2cdc3c --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MemberSelectionWriter.java @@ -0,0 +1,92 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.CascadeValue; +import com.epam.jsdmx.infomodel.sdmx30.LocalisedMemberValue; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.MemberValue; +import com.epam.jsdmx.infomodel.sdmx30.SelectionValue; +import com.epam.jsdmx.infomodel.sdmx30.TimeRangeValue; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections.CollectionUtils; + +public class MemberSelectionWriter { + private final DateTimeWriter dateTimeWriter; + + public MemberSelectionWriter(DateTimeWriter dateTimeWriter) { + this.dateTimeWriter = dateTimeWriter; + } + + public void writeMemberSelections(JsonGenerator jsonGenerator, List memberSelections) throws IOException { + if (CollectionUtils.isNotEmpty(memberSelections)) { + jsonGenerator.writeFieldName(StructureUtils.COMPONENTS); + jsonGenerator.writeStartArray(); + for (MemberSelection memberSelection : memberSelections) { + if (memberSelection != null) { + jsonGenerator.writeStartObject(); + + jsonGenerator.writeStringField(StructureUtils.ID, memberSelection.getComponentId()); + jsonGenerator.writeBooleanField(StructureUtils.INCLUDE, memberSelection.isIncluded()); + jsonGenerator.writeBooleanField(StructureUtils.REMOVE_PREFIX, memberSelection.isRemovePrefix()); + writeSelectionValues(jsonGenerator, memberSelection.getSelectionValues()); + + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } + + public void writeSelectionValues(JsonGenerator jsonGenerator, List selectionValues) throws IOException { + if (CollectionUtils.isNotEmpty(selectionValues)) { + List timeRanges = selectionValues.stream().filter(Objects::nonNull) + .filter(TimeRangeValue.class::isInstance) + .collect(Collectors.toList()); + dateTimeWriter.writeTimeRanges(jsonGenerator, timeRanges); + + List memberValues = selectionValues.stream().filter(Objects::nonNull) + .filter(value -> !(value instanceof TimeRangeValue)) + .collect(Collectors.toList()); + writeMemberValues(jsonGenerator, memberValues); + } + } + + private void writeMemberValues(JsonGenerator jsonGenerator, List memberValues) throws IOException { + if (CollectionUtils.isNotEmpty(memberValues)) { + jsonGenerator.writeFieldName(StructureUtils.VALUES); + jsonGenerator.writeStartArray(); + for (SelectionValue selectionValue : memberValues) { + jsonGenerator.writeStartObject(); + if (selectionValue instanceof MemberValue) { + MemberValue memberValue = (MemberValue) selectionValue; + jsonGenerator.writeStringField(StructureUtils.VALUE, memberValue.getValue()); + + CascadeValue cascadeValue = memberValue.getCascadeValue(); + if (StructureUtils.CASCADE_VALUE_TYPE_STRING.get(cascadeValue) != null) { + jsonGenerator.writeStringField(StructureUtils.CASCADE_VALUES, StructureUtils.CASCADE_VALUE_TYPE_STRING.get(cascadeValue)); + } + } + if (selectionValue instanceof LocalisedMemberValue) { + LocalisedMemberValue memberValue = (LocalisedMemberValue) selectionValue; + jsonGenerator.writeStringField(StructureUtils.VALUE, memberValue.getValue()); + + String locale = memberValue.getLocale(); + if (locale != null) { + jsonGenerator.writeStringField(StructureUtils.LANG, locale); + } + } + dateTimeWriter.writeValidDate(jsonGenerator, selectionValue.getValidFrom(), StructureUtils.VALID_FROM); + dateTimeWriter.writeValidDate(jsonGenerator, selectionValue.getValidTo(), StructureUtils.VALID_TO); + + jsonGenerator.writeEndObject(); + } + jsonGenerator.writeEndArray(); + + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetaWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetaWriter.java new file mode 100644 index 0000000..b2870f3 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetaWriter.java @@ -0,0 +1,78 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.util.List; +import java.util.Locale; +import java.util.Locale.LanguageRange; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultHeaderProvider; +import com.epam.jsdmx.serializer.sdmx30.common.Header; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.SneakyThrows; + +public class MetaWriter { + + private final List languagePriorities; + private final DefaultHeaderProvider defaultHeaderProvider; + + public MetaWriter(List languagePriorities, DefaultHeaderProvider defaultHeaderProvider) { + this.languagePriorities = languagePriorities; + this.defaultHeaderProvider = defaultHeaderProvider; + } + + @SneakyThrows + public void writeHeader(JsonGenerator jsonGenerator, Header header) { + if (header == null) { + return; + } + jsonGenerator.writeFieldName(StructureUtils.META); + jsonGenerator.writeStartObject(); + if (header.getSchema() != null) { + jsonGenerator.writeStringField(StructureUtils.SCHEMA, header.getSchema().toString()); + } + if (header.getId() != null) { + jsonGenerator.writeStringField(StructureUtils.ID, header.getId()); + } + Boolean isTest = header.isTest(); + if (isTest != null) { + jsonGenerator.writeBooleanField(StructureUtils.TEST, isTest); + } + if (header.getPrepared() != null) { + jsonGenerator.writeStringField(StructureUtils.PREPARED, header.getPrepared().toString()); + } + jsonGenerator.writeArrayFieldStart(StructureUtils.CONTENT_LANGUAGES); + for (Locale locale : header.getContentLanguages()) { + jsonGenerator.writeString(locale.toString()); + } + jsonGenerator.writeEndArray(); + + final InternationalString name = header.getName(); + if (name != null) { + jsonGenerator.writeStringField(StructureUtils.NAME, name.getForRanges(languagePriorities)); + StructureUtils.writeInternationalString(jsonGenerator, name, StructureUtils.NAMES); + } + + writeParty(jsonGenerator, header.getSender()); + jsonGenerator.writeEndObject(); + } + + public void writeDefaultHeader(JsonGenerator jsonGenerator) { + Header header = defaultHeaderProvider.provide(); + writeHeader(jsonGenerator, header); + } + + @SneakyThrows + private void writeParty(JsonGenerator jsonGenerator, Party party) { + jsonGenerator.writeFieldName(StructureUtils.SENDER); + jsonGenerator.writeStartObject(); + if (party.getId() != null) { + jsonGenerator.writeStringField(StructureUtils.ID, party.getId()); + } + if (party.getName() != null) { + jsonGenerator.writeStringField(StructureUtils.NAME, party.getName().getForDefaultLocale()); + } + jsonGenerator.writeEndObject(); + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataConstraintWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataConstraintWriter.java new file mode 100644 index 0000000..5fdece0 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataConstraintWriter.java @@ -0,0 +1,147 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.MetadataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.MetadataTargetRegion; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendar; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections.CollectionUtils; + +public class MetadataConstraintWriter extends MaintainableWriter { + + private final MemberSelectionWriter memberSelectionWriter; + private final ReferenceAdapter referenceAdapter; + + public MetadataConstraintWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + MemberSelectionWriter memberSelectionWriter, + ReferenceAdapter referenceAdapter) { + super(versionableWriter, linksWriter); + this.memberSelectionWriter = memberSelectionWriter; + this.referenceAdapter = referenceAdapter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, MetadataConstraint metadataConstraint) throws IOException { + super.writeFields(jsonGenerator, metadataConstraint); + jsonGenerator.writeStringField(StructureUtils.ROLE, "Allowed"); + + List metadataTargetRegions = metadataConstraint.getMetadataTargetRegions(); + writeMetadataTargetRegions(jsonGenerator, metadataTargetRegions); + + ReleaseCalendar releaseCalendar = metadataConstraint.getReleaseCalendar(); + writeReleaseCalendar(jsonGenerator, releaseCalendar); + + List constrainedArtefacts = metadataConstraint.getConstrainedArtefacts(); + writeConstrainedArtefacts(jsonGenerator, constrainedArtefacts); + + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getMetadataConstraints(); + } + + @Override + protected String getArrayName() { + return StructureUtils.METADATA_CONSTRAINTS; + } + + private void writeConstrainedArtefacts(JsonGenerator jsonGenerator, List constrainedArtefacts) throws IOException { + if (CollectionUtils.isNotEmpty(constrainedArtefacts)) { + jsonGenerator.writeFieldName(StructureUtils.CONSTRAINT_ATTACHMENT); + jsonGenerator.writeStartObject(); + Optional providerRef = StructureUtils.getArtefactReferenceByStructureClass( + constrainedArtefacts, + StructureClassImpl.METADATA_PROVIDER + ); + if (providerRef.isPresent()) { + jsonGenerator.writeStringField(StructureUtils.METADATA_PROVIDER, referenceAdapter.toAdaptedUrn(providerRef.get())); + } + + List metadataSets = StructureUtils.getArtefactReferencesByStructureClass(constrainedArtefacts, StructureClassImpl.METADATA_SET); + StructureUtils.writeArtefactReferences(jsonGenerator, metadataSets, StructureUtils.METADATA_SETS, referenceAdapter); + + List metadataStructures = StructureUtils.getArtefactReferencesByStructureClass( + constrainedArtefacts, + StructureClassImpl.METADATA_STRUCTURE + ); + StructureUtils.writeArtefactReferences(jsonGenerator, metadataStructures, StructureUtils.METADATA_STRUCTURES, referenceAdapter); + + List metadataflows = StructureUtils.getArtefactReferencesByStructureClass(constrainedArtefacts, StructureClassImpl.METADATAFLOW); + StructureUtils.writeArtefactReferences(jsonGenerator, metadataflows, StructureUtils.METADATAFLOWS, referenceAdapter); + + List metadataProvisionAgreements = StructureUtils.getArtefactReferencesByStructureClass( + constrainedArtefacts, + StructureClassImpl.METADATA_PROVISION_AGREEMENT + ); + StructureUtils.writeArtefactReferences(jsonGenerator, metadataProvisionAgreements, StructureUtils.METADATA_PROVISION_AGREEMENTS, referenceAdapter); + + jsonGenerator.writeEndObject(); + } + } + + private void writeMetadataTargetRegions(JsonGenerator jsonGenerator, List metadataTargetRegions) throws IOException { + if (CollectionUtils.isNotEmpty(metadataTargetRegions)) { + jsonGenerator.writeFieldName(StructureUtils.METADATA_TARGET_REGIONS); + jsonGenerator.writeStartArray(); + for (MetadataTargetRegion metadataTargetRegion : metadataTargetRegions) { + if (metadataTargetRegion != null) { + jsonGenerator.writeStartObject(); + + jsonGenerator.writeBooleanField(StructureUtils.INCLUDE, metadataTargetRegion.isIncluded()); + + Instant validFrom = metadataTargetRegion.getValidFrom(); + if (validFrom != null) { + jsonGenerator.writeStringField(StructureUtils.VALID_FROM, StructureUtils.mapInstantToString(validFrom)); + } + + Instant validTo = metadataTargetRegion.getValidTo(); + if (validTo != null) { + jsonGenerator.writeStringField(StructureUtils.VALID_TO, StructureUtils.mapInstantToString(validTo)); + } + + List memberSelections = metadataTargetRegion.getMemberSelections(); + memberSelectionWriter.writeMemberSelections(jsonGenerator, memberSelections); + + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } + + private void writeReleaseCalendar(JsonGenerator jsonGenerator, ReleaseCalendar releaseCalendar) throws IOException { + if (releaseCalendar != null) { + jsonGenerator.writeFieldName(StructureUtils.RELEASE_CALENDAR); + jsonGenerator.writeStartObject(); + + String tolerance = releaseCalendar.getTolerance(); + if (tolerance != null) { + jsonGenerator.writeStringField(StructureUtils.TOLERANCE, tolerance); + } + + String offset = releaseCalendar.getOffset(); + if (offset != null) { + jsonGenerator.writeStringField(StructureUtils.OFFSET, offset); + } + + String periodicity = releaseCalendar.getPeriodicity(); + if (periodicity != null) { + jsonGenerator.writeStringField(StructureUtils.PERIODICITY, periodicity); + } + jsonGenerator.writeEndObject(); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataProviderSchemeWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataProviderSchemeWriter.java new file mode 100644 index 0000000..48a49cc --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataProviderSchemeWriter.java @@ -0,0 +1,38 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderScheme; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class MetadataProviderSchemeWriter extends MaintainableWriter { + + private final OrganisationWriter organisationWriter; + + public MetadataProviderSchemeWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + OrganisationWriter organisationWriter) { + super(versionableWriter, linksWriter); + this.organisationWriter = organisationWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, MetadataProviderScheme metadataProviderScheme) throws IOException { + super.writeFields(jsonGenerator, metadataProviderScheme); + jsonGenerator.writeBooleanField(StructureUtils.IS_PARTIAL, metadataProviderScheme.isPartial()); + organisationWriter.writeOrganisation(jsonGenerator, metadataProviderScheme.getItems(), StructureUtils.METADATA_PROVIDERS); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getMetadataProviderSchemes(); + } + + @Override + protected String getArrayName() { + return StructureUtils.METADATA_PROVIDER_SCHEMES; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataProvisionAgreementWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataProvisionAgreementWriter.java new file mode 100644 index 0000000..fadb129 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataProvisionAgreementWriter.java @@ -0,0 +1,48 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProvisionAgreement; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class MetadataProvisionAgreementWriter extends MaintainableWriter { + + private final ReferenceAdapter referenceAdapter; + + public MetadataProvisionAgreementWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + ReferenceAdapter referenceAdapter) { + super(versionableWriter, linksWriter); + this.referenceAdapter = referenceAdapter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, MetadataProvisionAgreement metadataProvisionAgreement) throws IOException { + super.writeFields(jsonGenerator, metadataProvisionAgreement); + + ArtefactReference dataProvider = metadataProvisionAgreement.getMetadataProvider(); + if (dataProvider != null) { + jsonGenerator.writeStringField(StructureUtils.METADATA_PROVIDER, referenceAdapter.adaptUrn(dataProvider.getUrn())); + } + + ArtefactReference controlledStructureUsage = metadataProvisionAgreement.getControlledStructureUsage(); + if (controlledStructureUsage != null) { + jsonGenerator.writeStringField(StructureUtils.METADATAFLOW, referenceAdapter.adaptUrn(controlledStructureUsage.getUrn())); + } + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getMetadataProvisionAgreements(); + } + + @Override + protected String getArrayName() { + return StructureUtils.METADATA_PROVISION_AGREEMENTS; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataStructureDefinitionWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataStructureDefinitionWriter.java new file mode 100644 index 0000000..bd9878e --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataStructureDefinitionWriter.java @@ -0,0 +1,77 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttribute; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinition; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class MetadataStructureDefinitionWriter extends MaintainableWriter { + + private final ComponentWriter componentWriter; + private final IdentifiableWriter identifiableWriter; + + public MetadataStructureDefinitionWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + ComponentWriter componentWriter, + IdentifiableWriter identifiableWriter) { + super(versionableWriter, linksWriter); + this.componentWriter = componentWriter; + this.identifiableWriter = identifiableWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, MetadataStructureDefinition metadataStructureDefinition) throws IOException { + super.writeFields(jsonGenerator, metadataStructureDefinition); + jsonGenerator.writeFieldName(StructureUtils.METADATA_STRUCTURE_COMPONENTS); + jsonGenerator.writeStartObject(); + writeMetadataAttributeList(jsonGenerator, metadataStructureDefinition.getAttributeDescriptor()); + jsonGenerator.writeEndObject(); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getMetadataStructureDefinitions(); + } + + @Override + protected String getArrayName() { + return StructureUtils.METADATA_STRUCTURES; + } + + private void writeMetadataAttributeList(JsonGenerator jsonGenerator, MetadataAttributeDescriptor attributeDescriptor) throws IOException { + if (attributeDescriptor != null) { + jsonGenerator.writeFieldName(StructureUtils.METADATA_ATTRIBUTE_LIST); + jsonGenerator.writeStartObject(); + identifiableWriter.write(jsonGenerator, attributeDescriptor); + List attributeDescriptorComponents = attributeDescriptor.getComponents(); + writeMetadataAttributes(jsonGenerator, attributeDescriptorComponents); + jsonGenerator.writeEndObject(); + } + } + + private void writeMetadataAttributes(JsonGenerator jsonGenerator, List attributeDescriptorComponents) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.METADATA_ATTRIBUTES); + jsonGenerator.writeStartArray(); + if (attributeDescriptorComponents != null && !attributeDescriptorComponents.isEmpty()) { + for (MetadataAttribute metadataAttribute : attributeDescriptorComponents) { + jsonGenerator.writeStartObject(); + componentWriter.write(jsonGenerator, metadataAttribute); + jsonGenerator.writeNumberField(StructureUtils.MAX_OCCURS, metadataAttribute.getMaxOccurs()); + jsonGenerator.writeNumberField(StructureUtils.MIN_OCCURS, metadataAttribute.getMinOccurs()); + jsonGenerator.writeBooleanField(StructureUtils.IS_PRESENTATIONAL, metadataAttribute.isPresentational()); + if (!(metadataAttribute.getHierarchy() == null || metadataAttribute.getHierarchy().isEmpty())) { + writeMetadataAttributes(jsonGenerator, metadataAttribute.getHierarchy()); + } + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataflowWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataflowWriter.java new file mode 100644 index 0000000..f1699ac --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/MetadataflowWriter.java @@ -0,0 +1,74 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableObjectSelection; +import com.epam.jsdmx.infomodel.sdmx30.Metadataflow; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; + +@Slf4j +public class MetadataflowWriter extends MaintainableWriter { + + private final ReferenceAdapter referenceAdapter; + + public MetadataflowWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + ReferenceAdapter referenceAdapter) { + super(versionableWriter, linksWriter); + this.referenceAdapter = referenceAdapter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, Metadataflow metadataflow) throws IOException { + super.writeFields(jsonGenerator, metadataflow); + if (metadataflow.getStructure() != null) { + jsonGenerator.writeStringField(StructureUtils.STRUCTURE, referenceAdapter.toAdaptedUrn(metadataflow.getStructure())); + } + + List selections = metadataflow.getSelections(); + writeSelections(jsonGenerator, selections); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getMetadataflows(); + } + + @Override + protected String getArrayName() { + return StructureUtils.METADATAFLOWS; + } + + private void writeSelections(JsonGenerator jsonGenerator, List selections) throws IOException { + if (CollectionUtils.isNotEmpty(selections)) { + List artefactReferences = selections.stream() + .filter(Objects::nonNull) + .flatMap(selection -> selection.getResolvesTo().stream()) + .collect(Collectors.toList()); + writeArtefactReferences(jsonGenerator, artefactReferences); + } + } + + private void writeArtefactReferences(JsonGenerator jsonGenerator, List artefactReferences) throws IOException { + if (CollectionUtils.isNotEmpty(artefactReferences)) { + jsonGenerator.writeFieldName(StructureUtils.TARGETS); + jsonGenerator.writeStartArray(); + for (ArtefactReference artefactReference : artefactReferences) { + if (artefactReference != null) { + jsonGenerator.writeString(referenceAdapter.toAdaptedUrn(artefactReference)); + } + } + jsonGenerator.writeEndArray(); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/NameableWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/NameableWriter.java new file mode 100644 index 0000000..96c6fb2 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/NameableWriter.java @@ -0,0 +1,54 @@ +package com.epam.jsdmx.json20.structure.writer; + +import static com.epam.jsdmx.json20.structure.writer.StructureUtils.writeInternationalString; + +import java.io.IOException; +import java.util.List; +import java.util.Locale; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.NameableArtefact; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class NameableWriter { + + private final IdentifiableWriter identifiableWriter; + private List languagePriorities; + + public NameableWriter(IdentifiableWriter identifiableWriter) { + this.identifiableWriter = identifiableWriter; + } + + public NameableWriter(IdentifiableWriter identifiableWriter, List languagePriorities) { + this.identifiableWriter = identifiableWriter; + this.languagePriorities = languagePriorities; + } + + public void write(JsonGenerator jsonGenerator, NameableArtefact artefact) throws IOException { + identifiableWriter.write(jsonGenerator, artefact); + writeName(jsonGenerator, artefact); + writeDescription(jsonGenerator, artefact); + } + + private void writeName(JsonGenerator jsonGenerator, NameableArtefact artefact) throws IOException { + writeI18nValue(artefact.getName(), jsonGenerator, StructureUtils.NAME, StructureUtils.NAMES); + } + + private void writeDescription(JsonGenerator jsonGenerator, NameableArtefact artefact) throws IOException { + writeI18nValue(artefact.getDescription(), jsonGenerator, StructureUtils.DESCRIPTION, StructureUtils.DESCRIPTIONS); + } + + private void writeI18nValue(InternationalString i18nString, + JsonGenerator jsonGenerator, + String localisedFieldName, + String allNamesField) throws IOException { + if (i18nString != null) { + final String value = StructureUtils.getLocalisedValue(i18nString, languagePriorities); + if (value != null) { + jsonGenerator.writeStringField(localisedFieldName, value); + } + writeInternationalString(jsonGenerator, i18nString, allNamesField); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/OrganisationSchemeMapWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/OrganisationSchemeMapWriter.java new file mode 100644 index 0000000..6138103 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/OrganisationSchemeMapWriter.java @@ -0,0 +1,45 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationSchemeMap; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class OrganisationSchemeMapWriter extends MaintainableWriter { + + private final AnnotableWriter annotableWriter; + private final ItemMapWriter itemMapWriter; + + public OrganisationSchemeMapWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + AnnotableWriter annotableWriter, + ItemMapWriter itemMapWriter) { + super(versionableWriter, linksWriter); + this.annotableWriter = annotableWriter; + this.itemMapWriter = itemMapWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, OrganisationSchemeMap organisationSchemeMap) throws IOException { + super.writeFields(jsonGenerator, organisationSchemeMap); + List itemMaps = organisationSchemeMap.getItemMaps(); + itemMapWriter.writeItemMaps(jsonGenerator, itemMaps, annotableWriter); + itemMapWriter.writeSource(jsonGenerator, organisationSchemeMap.getSource()); + itemMapWriter.writeTarget(jsonGenerator, organisationSchemeMap.getTarget()); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getOrganisationSchemeMaps(); + } + + @Override + protected String getArrayName() { + return StructureUtils.ORGANISATION_SCHEME_MAPS; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/OrganisationUnitSchemeWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/OrganisationUnitSchemeWriter.java new file mode 100644 index 0000000..2654529 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/OrganisationUnitSchemeWriter.java @@ -0,0 +1,45 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnit; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitScheme; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class OrganisationUnitSchemeWriter extends MaintainableWriter { + + private final OrganisationWriter organisationWriter; + + public OrganisationUnitSchemeWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + OrganisationWriter organisationWriter) { + super(versionableWriter, linksWriter); + this.organisationWriter = organisationWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, OrganisationUnitScheme organisationUnitScheme) throws IOException { + OrganisationUnitSchemeImpl organisationUnitSchemeImpl = (OrganisationUnitSchemeImpl) organisationUnitScheme; + organisationUnitSchemeImpl.setVersion(Version.createFromString(StructureUtils.DEFAULT_VERSION)); + super.writeFields(jsonGenerator, organisationUnitSchemeImpl); + jsonGenerator.writeBooleanField(StructureUtils.IS_PARTIAL, organisationUnitSchemeImpl.isPartial()); + List items = organisationUnitSchemeImpl.getItems(); + organisationWriter.writeOrganisation(jsonGenerator, items, StructureUtils.ORGANISATION_UNITS); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getOrganisationUnitSchemes(); + } + + @Override + protected String getArrayName() { + return StructureUtils.ORGANISATION_UNIT_SCHEMES; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/OrganisationWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/OrganisationWriter.java new file mode 100644 index 0000000..b4d2c75 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/OrganisationWriter.java @@ -0,0 +1,59 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.epam.jsdmx.infomodel.sdmx30.Contact; +import com.epam.jsdmx.infomodel.sdmx30.Organisation; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.AllArgsConstructor; +import org.apache.commons.collections.CollectionUtils; + +@AllArgsConstructor +public class OrganisationWriter { + + private final ContactsWriter contactsWriter; + private final NameableWriter nameableWriter; + + > void writeOrganisation(JsonGenerator jsonGenerator, + List organisationItems, + String organisationName) throws IOException { + if (CollectionUtils.isNotEmpty(organisationItems)) { + Map parentIdWithHierarchy = new HashMap<>(); + for (T organisat : organisationItems) { + List> children = organisat.getHierarchy(); + if (CollectionUtils.isNotEmpty(children)) { + for (Organisation child : children) { + parentIdWithHierarchy.put(child.getId(), organisat.getId()); + } + } + } + + jsonGenerator.writeFieldName(organisationName); + jsonGenerator.writeStartArray(); + for (T organisation : organisationItems) { + writeOrganisation(jsonGenerator, parentIdWithHierarchy, organisation); + } + jsonGenerator.writeEndArray(); + } + } + + private > void writeOrganisation(JsonGenerator jsonGenerator, + Map parentIdWithHierarchy, + T organisation) throws IOException { + if (organisation != null) { + jsonGenerator.writeStartObject(); + nameableWriter.write(jsonGenerator, organisation); + List contacts = organisation.getContacts(); + contactsWriter.writeContacts(jsonGenerator, contacts); + String id = organisation.getId(); + if (parentIdWithHierarchy.containsKey(id)) { + jsonGenerator.writeStringField(StructureUtils.PARENT, parentIdWithHierarchy.get(id)); + } + jsonGenerator.writeEndObject(); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ProcessWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ProcessWriter.java new file mode 100644 index 0000000..7a52146 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ProcessWriter.java @@ -0,0 +1,172 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Computation; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.Process; +import com.epam.jsdmx.infomodel.sdmx30.ProcessArtefact; +import com.epam.jsdmx.infomodel.sdmx30.ProcessStep; +import com.epam.jsdmx.infomodel.sdmx30.Transition; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections.CollectionUtils; + +public class ProcessWriter extends MaintainableWriter { + + private final NameableWriter nameableWriter; + private final AnnotableWriter annotableWriter; + private final IdentifiableWriter identifiableWriter; + + + public ProcessWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + IdentifiableWriter identifiableWriter) { + super(versionableWriter, linksWriter); + this.nameableWriter = nameableWriter; + this.annotableWriter = annotableWriter; + this.identifiableWriter = identifiableWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, Process process) throws IOException { + super.writeFields(jsonGenerator, process); + List steps = process.getSteps(); + writeProcessSteps(jsonGenerator, steps); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getProcesses(); + } + + @Override + protected String getArrayName() { + return StructureUtils.PROCESSES; + } + + private void writeProcessSteps(JsonGenerator jsonGenerator, List steps) throws IOException { + if (CollectionUtils.isNotEmpty(steps)) { + jsonGenerator.writeFieldName(StructureUtils.PROCESS_STEPS); + jsonGenerator.writeStartArray(); + for (ProcessStep processStep : steps) { + jsonGenerator.writeStartObject(); + + nameableWriter.write(jsonGenerator, processStep); + + Computation computation = processStep.getComputation(); + writeComputation(jsonGenerator, computation); + + List transitions = processStep.getTransitions(); + writeTransitions(jsonGenerator, transitions); + + List outputs = processStep.getOutputs(); + writeInputOutput(jsonGenerator, outputs, StructureUtils.OUTPUTS); + + List inputs = processStep.getInputs(); + writeInputOutput(jsonGenerator, inputs, StructureUtils.INPUTS); + + List children = processStep.getChildren(); + writeProcessSteps(jsonGenerator, children); + jsonGenerator.writeEndObject(); + } + jsonGenerator.writeEndArray(); + } + } + + private void writeInputOutput(JsonGenerator jsonGenerator, List processArtefacts, String inputOutputName) throws IOException { + if (CollectionUtils.isNotEmpty(processArtefacts)) { + jsonGenerator.writeFieldName(inputOutputName); + jsonGenerator.writeStartArray(); + for (ProcessArtefact processArtefact : processArtefacts) { + jsonGenerator.writeStartObject(); + + String localId = processArtefact.getLocalId(); + if (localId != null) { + jsonGenerator.writeStringField(StructureUtils.LOCAL_ID, localId); + } + + annotableWriter.write(jsonGenerator, processArtefact); + + ArtefactReference artefact = processArtefact.getArtefact(); + if (artefact != null) { + jsonGenerator.writeStringField(StructureUtils.OBJECT_REFERENCE, artefact.getUrn()); + } + + jsonGenerator.writeEndObject(); + } + jsonGenerator.writeEndArray(); + } + } + + private void writeTransitions(JsonGenerator jsonGenerator, List transitions) throws IOException { + if (CollectionUtils.isNotEmpty(transitions)) { + jsonGenerator.writeFieldName(StructureUtils.TRANSITIONS); + jsonGenerator.writeStartArray(); + for (Transition transition : transitions) { + jsonGenerator.writeStartObject(); + + identifiableWriter.write(jsonGenerator, transition); + + String localId = transition.getLocalId(); + if (localId != null) { + jsonGenerator.writeStringField(StructureUtils.LOCAL_ID, localId); + } + + InternationalString condition = transition.getCondition(); + if (condition != null) { + jsonGenerator.writeStringField( + StructureUtils.CONDITION, + condition.getForDefaultLocale() + ); + StructureUtils.writeInternationalString(jsonGenerator, condition, StructureUtils.CONDITIONS); + } + + String targetProcessStep = transition.getTargetProcessStep(); + if (targetProcessStep != null) { + jsonGenerator.writeStringField(StructureUtils.TARGET_STEP, targetProcessStep); + } + + jsonGenerator.writeEndObject(); + } + jsonGenerator.writeEndArray(); + } + } + + private void writeComputation(JsonGenerator jsonGenerator, Computation computation) throws IOException { + if (computation != null) { + jsonGenerator.writeFieldName(StructureUtils.COMPUTATION); + jsonGenerator.writeStartObject(); + + if (computation.getLocalId() != null) { + jsonGenerator.writeStringField(StructureUtils.LOCAL_ID, computation.getLocalId()); + } + if (computation.getSoftwareLanguage() != null) { + jsonGenerator.writeStringField(StructureUtils.SOFTWARE_LANGUAGE, computation.getSoftwareLanguage()); + } + if (computation.getSoftwarePackage() != null) { + jsonGenerator.writeStringField(StructureUtils.SOFTWARE_PACKAGE, computation.getSoftwarePackage()); + } + if (computation.getSoftwareVersion() != null) { + jsonGenerator.writeStringField(StructureUtils.SOFTWARE_VERSION, computation.getSoftwareVersion()); + } + + annotableWriter.write(jsonGenerator, computation); + + if (computation.getDescription() != null) { + jsonGenerator.writeStringField( + StructureUtils.DESCRIPTION, + computation.getDescription().getForDefaultLocale() + ); + StructureUtils.writeInternationalString(jsonGenerator, computation.getDescription(), StructureUtils.DESCRIPTIONS); + } + jsonGenerator.writeEndObject(); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ProvisionAgreementWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ProvisionAgreementWriter.java new file mode 100644 index 0000000..0a08017 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ProvisionAgreementWriter.java @@ -0,0 +1,46 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ProvisionAgreement; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class ProvisionAgreementWriter extends MaintainableWriter { + + private final ReferenceAdapter referenceAdapter; + + public ProvisionAgreementWriter(VersionableWriter versionableWriter, LinksWriter linksWriter, ReferenceAdapter referenceAdapter) { + super(versionableWriter, linksWriter); + this.referenceAdapter = referenceAdapter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, ProvisionAgreement provisionAgreement) throws IOException { + super.writeFields(jsonGenerator, provisionAgreement); + + ArtefactReference dataProvider = provisionAgreement.getDataProvider(); + if (dataProvider != null) { + jsonGenerator.writeStringField(StructureUtils.DATA_PROVIDER, referenceAdapter.toAdaptedUrn(dataProvider)); + } + + ArtefactReference controlledStructureUsage = provisionAgreement.getControlledStructureUsage(); + if (controlledStructureUsage != null) { + jsonGenerator.writeStringField(StructureUtils.DATAFLOW, referenceAdapter.toAdaptedUrn(controlledStructureUsage)); + } + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getProvisionAgreements(); + } + + @Override + protected String getArrayName() { + return StructureUtils.PROVISION_AGREEMENTS; + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ReportingTaxonomyMapWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ReportingTaxonomyMapWriter.java new file mode 100644 index 0000000..f45a694 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ReportingTaxonomyMapWriter.java @@ -0,0 +1,45 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyMap; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class ReportingTaxonomyMapWriter extends MaintainableWriter { + + private final AnnotableWriter annotableWriter; + private final ItemMapWriter itemMapWriter; + + public ReportingTaxonomyMapWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + AnnotableWriter annotableWriter, + ItemMapWriter itemMapWriter) { + super(versionableWriter, linksWriter); + this.annotableWriter = annotableWriter; + this.itemMapWriter = itemMapWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, ReportingTaxonomyMap reportingTaxonomyMap) throws IOException { + super.writeFields(jsonGenerator, reportingTaxonomyMap); + List itemMaps = reportingTaxonomyMap.getItemMaps(); + itemMapWriter.writeItemMaps(jsonGenerator, itemMaps, annotableWriter); + itemMapWriter.writeSource(jsonGenerator, reportingTaxonomyMap.getSource()); + itemMapWriter.writeTarget(jsonGenerator, reportingTaxonomyMap.getTarget()); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getReportingTaxonomyMaps(); + } + + @Override + protected String getArrayName() { + return StructureUtils.REPORTING_TAXONOMY_MAPS; + } +} \ No newline at end of file diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ReportingTaxonomyWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ReportingTaxonomyWriter.java new file mode 100644 index 0000000..ab09918 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ReportingTaxonomyWriter.java @@ -0,0 +1,73 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Item; +import com.epam.jsdmx.infomodel.sdmx30.ReportingCategory; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomy; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections.CollectionUtils; + +public class ReportingTaxonomyWriter extends MaintainableWriter { + + private final NameableWriter nameableWriter; + private final ReferenceAdapter referenceAdapter; + + public ReportingTaxonomyWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + NameableWriter nameableWriter, + ReferenceAdapter referenceAdapter) { + super(versionableWriter, linksWriter); + this.nameableWriter = nameableWriter; + this.referenceAdapter = referenceAdapter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, ReportingTaxonomy reportingTaxonomy) throws IOException { + super.writeFields(jsonGenerator, reportingTaxonomy); + jsonGenerator.writeBooleanField(StructureUtils.IS_PARTIAL, reportingTaxonomy.isPartial()); + List items = reportingTaxonomy.getItems(); + writeReportingCategories(jsonGenerator, items); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getReportingTaxonomies(); + } + + @Override + protected String getArrayName() { + return StructureUtils.REPORTING_TAXONOMIES; + } + + private void writeReportingCategories(JsonGenerator jsonGenerator, List items) throws IOException { + if (CollectionUtils.isNotEmpty(items)) { + jsonGenerator.writeFieldName(StructureUtils.REPORTING_CATEGORIES); + jsonGenerator.writeStartArray(); + for (ReportingCategory reportingCategory : items) { + if (reportingCategory != null) { + jsonGenerator.writeStartObject(); + + nameableWriter.write(jsonGenerator, reportingCategory); + + List structures = reportingCategory.getStructures(); + StructureUtils.writeArtefactReferences(jsonGenerator, structures, StructureUtils.STRUCTURAL_METADATA, referenceAdapter); + + List flows = reportingCategory.getFlows(); + StructureUtils.writeArtefactReferences(jsonGenerator, flows, StructureUtils.PROVISIONING_METADATA, referenceAdapter); + + List hierarchy = reportingCategory.getHierarchy(); + writeReportingCategories(jsonGenerator, (List) hierarchy); + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/RepresentationMapWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/RepresentationMapWriter.java new file mode 100644 index 0000000..5e4f02f --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/RepresentationMapWriter.java @@ -0,0 +1,140 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueTypeRepresentation; +import com.epam.jsdmx.infomodel.sdmx30.ListReferenceValueRepresentation; +import com.epam.jsdmx.infomodel.sdmx30.MappedValue; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMap; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapping; +import com.epam.jsdmx.infomodel.sdmx30.TargetValue; +import com.epam.jsdmx.infomodel.sdmx30.ValueRepresentation; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class RepresentationMapWriter extends MaintainableWriter { + + private final AnnotableWriter annotableWriter; + private final ReferenceAdapter referenceAdapter; + + public RepresentationMapWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + AnnotableWriter annotableWriter, + ReferenceAdapter referenceAdapter) { + super(versionableWriter, linksWriter); + this.annotableWriter = annotableWriter; + this.referenceAdapter = referenceAdapter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, RepresentationMap representationMap) throws IOException { + super.writeFields(jsonGenerator, representationMap); + writeValueRepresentationList(jsonGenerator, representationMap.getSource(), StructureUtils.SOURCE); + writeValueRepresentationList(jsonGenerator, representationMap.getTarget(), StructureUtils.TARGET); + writeRepresentationMappings(jsonGenerator, representationMap.getRepresentationMappings()); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getRepresentationMaps(); + } + + @Override + protected String getArrayName() { + return StructureUtils.REPRESENTATION_MAPS; + } + + private void writeRepresentationMappings(JsonGenerator jsonGenerator, List representationMappings) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.REPRESENTATION_MAPPINGS); + jsonGenerator.writeStartArray(); + if (representationMappings != null && !representationMappings.isEmpty()) { + for (RepresentationMapping representationMapping : representationMappings) { + jsonGenerator.writeStartObject(); + annotableWriter.write(jsonGenerator, representationMapping); + Instant validTo = representationMapping.getValidTo(); + if (validTo != null) { + jsonGenerator.writeStringField( + StructureUtils.VALID_TO, + StructureUtils.mapInstantToString(validTo) + ); + } + Instant validFrom = representationMapping.getValidFrom(); + if (validFrom != null) { + jsonGenerator.writeStringField( + StructureUtils.VALID_FROM, + StructureUtils.mapInstantToString(validFrom) + ); + } + writeSourceValues(jsonGenerator, representationMapping.getSourceValues()); + writeTargetValues(jsonGenerator, representationMapping.getTargetValues()); + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + + private void writeTargetValues(JsonGenerator jsonGenerator, List targetValues) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.TARGET_VALUES); + jsonGenerator.writeStartArray(); + if (targetValues != null && !targetValues.isEmpty()) { + for (TargetValue targetValue : targetValues) { + jsonGenerator.writeString(targetValue.getValue()); + } + } + jsonGenerator.writeEndArray(); + } + + private void writeSourceValues(JsonGenerator jsonGenerator, List sourceValues) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.SOURCE_VALUES); + jsonGenerator.writeStartArray(); + if (sourceValues != null && !sourceValues.isEmpty()) { + for (MappedValue mappedValue : sourceValues) { + jsonGenerator.writeStartObject(); + if (mappedValue.getValue() != null) { + jsonGenerator.writeStringField(StructureUtils.VALUE, mappedValue.getValue()); + } + jsonGenerator.writeBooleanField(StructureUtils.IS_REG_EX, mappedValue.isRegEx()); + jsonGenerator.writeNumberField(StructureUtils.START_INDEX, mappedValue.getStartIndex()); + jsonGenerator.writeNumberField(StructureUtils.END_INDEX, mappedValue.getEndIndex()); + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + + private void writeValueRepresentationList(JsonGenerator jsonGenerator, + List valueRepresentations, + String valueRepresentationName) throws IOException { + if (valueRepresentations != null && !valueRepresentations.isEmpty()) { + jsonGenerator.writeFieldName(valueRepresentationName); + jsonGenerator.writeStartArray(); + for (ValueRepresentation valueRepresentation : valueRepresentations) { + jsonGenerator.writeStartObject(); + if (valueRepresentation instanceof ListReferenceValueRepresentation) { + ListReferenceValueRepresentation listReferenceValueRepresentation = (ListReferenceValueRepresentation) valueRepresentation; + String urn = Optional.ofNullable(listReferenceValueRepresentation.getListReference()) + .map(referenceAdapter::toAdaptedUrn) + .orElse(null); + if (urn != null) { + jsonGenerator.writeStringField(StructureUtils.CODE_LIST, urn); + } + } else if (valueRepresentation instanceof FacetValueTypeRepresentation) { + FacetValueTypeRepresentation facetValueTypeRepresentation = (FacetValueTypeRepresentation) valueRepresentation; + FacetValueType facetType = facetValueTypeRepresentation.getType(); + if (facetType != null) { + jsonGenerator.writeStringField(StructureUtils.DATA_TYPE, facetType.value()); + } + } + jsonGenerator.writeEndObject(); + } + jsonGenerator.writeEndArray(); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/RepresentationWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/RepresentationWriter.java new file mode 100644 index 0000000..f6b15af --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/RepresentationWriter.java @@ -0,0 +1,112 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Facet; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.infomodel.sdmx30.SentinelValue; +import com.epam.jsdmx.infomodel.sdmx30.TextFormatImpl; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class RepresentationWriter { + + private final ReferenceAdapter referenceAdapter; + + public RepresentationWriter(ReferenceAdapter referenceAdapter) { + this.referenceAdapter = referenceAdapter; + } + + public void writeRepresentation(JsonGenerator jsonGenerator, + Representation representation, + String representationName) throws IOException { + jsonGenerator.writeFieldName(representationName); + jsonGenerator.writeStartObject(); + if (representation != null) { + if (representation.isEnumerated()) { + jsonGenerator.writeStringField(StructureUtils.ENUMERATION, referenceAdapter.toAdaptedUrn(representation.enumerated())); + } else { + Set facets = representation.nonEnumerated(); + TextFormatImpl textFormat = new TextFormatImpl(facets); + jsonGenerator.writeFieldName(StructureUtils.FORMAT); + jsonGenerator.writeStartObject(); + + writeTextFormat(jsonGenerator, textFormat); + + writeSentinelValues(jsonGenerator, textFormat); + + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndObject(); + } + + private void writeSentinelValues(JsonGenerator jsonGenerator, TextFormatImpl textFormat) throws IOException { + if (textFormat.hasSentinelValues()) { + Optional> sentinelValues = textFormat.getSentinelValues(); + if (sentinelValues.isPresent()) { + List sentinelValueList = sentinelValues.get(); + jsonGenerator.writeFieldName(StructureUtils.SENTINEL_VALUES); + jsonGenerator.writeStartArray(); + for (SentinelValue sentinelValue : sentinelValueList) { + writeSentinelValue(jsonGenerator, sentinelValue); + } + jsonGenerator.writeEndArray(); + } + } + } + + private void writeSentinelValue(JsonGenerator jsonGenerator, SentinelValue sentinelValue) throws IOException { + jsonGenerator.writeStartObject(); + String value = sentinelValue.getValue(); + if (value != null) { + jsonGenerator.writeStringField(StructureUtils.VALUE, value); + + writeName(jsonGenerator, sentinelValue); + + writeDescription(jsonGenerator, sentinelValue); + } + jsonGenerator.writeEndObject(); + } + + private void writeDescription(JsonGenerator jsonGenerator, SentinelValue sentinelValue) throws IOException { + InternationalString description = sentinelValue.getDescription(); + if (description != null) { + jsonGenerator.writeStringField( + StructureUtils.DESCRIPTION, + description.getForDefaultLocale() + ); + } + StructureUtils.writeInternationalString(jsonGenerator, description, StructureUtils.DESCRIPTIONS); + } + + private void writeName(JsonGenerator jsonGenerator, SentinelValue sentinelValue) throws IOException { + InternationalString name = sentinelValue.getName(); + if (name != null) { + jsonGenerator.writeStringField( + StructureUtils.NAME, + name.getForDefaultLocale() + ); + } + StructureUtils.writeInternationalString(jsonGenerator, name, StructureUtils.NAMES); + } + + private void writeTextFormat(JsonGenerator jsonGenerator, TextFormatImpl textFormat) throws IOException { + + StructureUtils.writeCommonFormatAttributes(jsonGenerator, textFormat); + Optional decimals = textFormat.getDecimals(); + if (decimals.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.DECIMALS, decimals.get()); + } + Optional multiLingual = textFormat.getIsMultiLingual(); + if (multiLingual.isPresent()) { + jsonGenerator.writeBooleanField(StructureUtils.IS_MULTI_LINGUAL, multiLingual.get()); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/StructureMapUtils.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/StructureMapUtils.java new file mode 100644 index 0000000..20c3c4b --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/StructureMapUtils.java @@ -0,0 +1,147 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.epam.jsdmx.infomodel.sdmx30.ComponentMap; +import com.epam.jsdmx.infomodel.sdmx30.ComponentMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.DateMap; +import com.epam.jsdmx.infomodel.sdmx30.DatePatternMap; +import com.epam.jsdmx.infomodel.sdmx30.EpochMap; +import com.epam.jsdmx.infomodel.sdmx30.FrequencyFormatMapping; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureMap; +import com.epam.jsdmx.infomodel.sdmx30.StructureMapImpl; + +import org.apache.commons.collections.CollectionUtils; + +public final class StructureMapUtils { + + private StructureMapUtils() { + } + + public static Map> getEpochWithMappedComponent(List epochMaps, List componentMaps) { + Map epochs = epochMaps.stream() + .collect(Collectors.toMap(EpochMap::getId, Function.identity())); + if (CollectionUtils.isNotEmpty(componentMaps)) { + return filterDateMapInComponentMaps(componentMaps, epochs).stream() + .collect(Collectors.groupingBy(componentMap -> epochs.get(componentMap.getRepresentationMap() + .getItemId()), transformComponentMapIntoMappedComponent())); + } + return Collections.emptyMap(); + } + + private static Collector> transformComponentMapIntoMappedComponent() { + return Collectors.mapping(map -> new MappedComponent( + map.getSource().get(0), + map.getTarget().get(0) + ), Collectors.toList()); + } + + private static List filterDateMapInComponentMaps(List componentMaps, Map maps) { + return componentMaps.stream() + .filter(Objects::nonNull) + .filter(componentMap -> componentMap.getRepresentationMap() != null) + .filter(componentMap -> maps.containsKey(componentMap.getRepresentationMap().getItemId())) + .collect(Collectors.toList()); + } + + public static Map> getDatePatternWithMappedComponent(List dateMap, List componentMaps) { + Map datePatterns = dateMap.stream() + .filter(datePatternMap -> datePatternMap.getId() != null) + .collect(Collectors.toMap(DatePatternMap::getId, Function.identity())); + if (CollectionUtils.isNotEmpty(componentMaps)) { + return filterDateMapInComponentMaps(componentMaps, datePatterns).stream() + .collect(Collectors.groupingBy(componentMap -> datePatterns.get(componentMap.getRepresentationMap() + .getItemId()), transformComponentMapIntoMappedComponent())); + } + return Collections.emptyMap(); + } + + public static List getFrequencyFormatMappings(List epochMaps, List datePatternMaps) { + List frequencyFormatMappings = new ArrayList<>(); + for (EpochMap epochMap : epochMaps) { + if (epochMap != null && epochMap.getMappedFrequencies() != null) { + frequencyFormatMappings.addAll(epochMap.getMappedFrequencies()); + } + } + for (DatePatternMap datePatternMap : datePatternMaps) { + if (datePatternMap != null && datePatternMap.getMappedFrequencies() != null) { + frequencyFormatMappings.addAll(datePatternMap.getMappedFrequencies()); + } + } + return frequencyFormatMappings; + } + + public static List getRepresentationMap(StructureMap structureMap) { + List epochIds = structureMap.getEpochMaps() + .stream() + .map(EpochMap::getId) + .collect(Collectors.toList()); + List datePatternIds = structureMap.getDatePatternMaps() + .stream() + .map(DatePatternMap::getId) + .collect(Collectors.toList()); + List nonRepresentationMapIds = Stream.concat(epochIds.stream(), datePatternIds.stream()) + .collect(Collectors.toList()); + List componentMaps = structureMap.getComponentMaps(); + return componentMaps == null ? null + : componentMaps.stream() + .filter(Objects::nonNull) + .filter(componentMap -> + componentMap.getRepresentationMap() == null + || !nonRepresentationMapIds.contains(componentMap.getRepresentationMap().getItemId())) + .collect(Collectors.toList()); + } + + public static List extractComponentMapFromDatePatternMap(Map mappedComponents, + StructureMapImpl structureMap) { + List componentMaps = new ArrayList<>(); + for (Map.Entry entrySet : mappedComponents + .entrySet()) { + ComponentMapImpl componentMapDP = new ComponentMapImpl(); + componentMapDP.setSource(List.of(entrySet.getValue() + .getSource())); + componentMapDP.setTarget(List.of(entrySet.getValue() + .getTarget())); + componentMapDP.setRepresentationMap( + new IdentifiableArtefactReferenceImpl(structureMap.getId(), structureMap.getOrganizationId(), structureMap.getVersion().toString(), + StructureClassImpl.DATE_PATTERN_MAP, entrySet.getKey() + .getId() + )); + componentMaps.add(componentMapDP); + } + return componentMaps; + } + + public static List extractComponentMapFromEpochMap(Map mappedComponents, StructureMapImpl structureMap) { + List componentMaps = new ArrayList<>(); + for (Map.Entry entrySet : mappedComponents + .entrySet()) { + ComponentMapImpl componentMapEpoch = new ComponentMapImpl(); + componentMapEpoch.setSource(List.of(entrySet.getValue() + .getSource())); + componentMapEpoch.setTarget(List.of(entrySet.getValue() + .getTarget())); + componentMapEpoch.setRepresentationMap( + new IdentifiableArtefactReferenceImpl( + structureMap.getId(), + structureMap.getOrganizationId(), + structureMap.getVersion().toString(), + StructureClassImpl.EPOCH_MAP, + entrySet.getKey() + .getId() + )); + componentMaps.add(componentMapEpoch); + } + return componentMaps; + } +} \ No newline at end of file diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/StructureMapWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/StructureMapWriter.java new file mode 100644 index 0000000..aadebfd --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/StructureMapWriter.java @@ -0,0 +1,255 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ComponentMap; +import com.epam.jsdmx.infomodel.sdmx30.DateMap; +import com.epam.jsdmx.infomodel.sdmx30.DatePatternMap; +import com.epam.jsdmx.infomodel.sdmx30.EpochMap; +import com.epam.jsdmx.infomodel.sdmx30.EpochPeriodType; +import com.epam.jsdmx.infomodel.sdmx30.FixedValueMap; +import com.epam.jsdmx.infomodel.sdmx30.FrequencyFormatMapping; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.StructureMap; +import com.epam.jsdmx.infomodel.sdmx30.YearStart; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections.CollectionUtils; + +public class StructureMapWriter extends MaintainableWriter { + + private final AnnotableWriter annotableWriter; + private final IdentifiableWriter identifiableWriter; + private final ReferenceAdapter referenceAdapter; + + public StructureMapWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + AnnotableWriter annotableWriter, + IdentifiableWriter identifiableWriter, + ReferenceAdapter referenceAdapter) { + super(versionableWriter, linksWriter); + this.annotableWriter = annotableWriter; + this.identifiableWriter = identifiableWriter; + this.referenceAdapter = referenceAdapter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, StructureMap structureMap) throws IOException { + super.writeFields(jsonGenerator, structureMap); + writeSource(jsonGenerator, structureMap.getSource()); + writeTarget(jsonGenerator, structureMap.getTarget()); + + Map> epochWithMappedComponent = StructureMapUtils.getEpochWithMappedComponent( + structureMap.getEpochMaps(), + structureMap.getComponentMaps() + ); + writeEpochMaps(jsonGenerator, epochWithMappedComponent); + Map> datePatternWithMappedComponent = StructureMapUtils.getDatePatternWithMappedComponent( + structureMap.getDatePatternMaps(), + structureMap.getComponentMaps() + ); + writeDatePatternMaps(jsonGenerator, datePatternWithMappedComponent); + List frequencyFormatMappings = StructureMapUtils.getFrequencyFormatMappings( + structureMap.getEpochMaps(), + structureMap.getDatePatternMaps() + ); + writeFrequencyFormatMappings(jsonGenerator, frequencyFormatMappings); + writeComponentMaps(jsonGenerator, StructureMapUtils.getRepresentationMap(structureMap)); + writeFixedValueMaps(jsonGenerator, structureMap.getFixedComponentMaps()); + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getStructureMaps(); + } + + @Override + protected String getArrayName() { + return StructureUtils.STRUCTURE_MAP; + } + + private void writeDateMap(JsonGenerator jsonGenerator, DateMap dateMap, List mappedComponents) throws IOException { + identifiableWriter.write(jsonGenerator, dateMap); + writeMappedComponents(jsonGenerator, mappedComponents); + jsonGenerator.writeStringField(StructureUtils.RESOLVE_PERIOD, dateMap.getResolvePeriod() + .toString()); + String frequencyDimension = dateMap.getFrequencyDimension(); + if (frequencyDimension != null) { + jsonGenerator.writeStringField(StructureUtils.FREQUENCY_DIMENSION, frequencyDimension); + } + String targetFrequencyId = dateMap.getTargetFrequencyId(); + if (targetFrequencyId != null) { + jsonGenerator.writeStringField(StructureUtils.TARGET_FREQUENCY_ID, targetFrequencyId); + } + List mappedFrequencies = dateMap.getMappedFrequencies(); + writeMappedFreq(jsonGenerator, mappedFrequencies); + YearStart yearStart = dateMap.getYearStart(); + jsonGenerator.writeFieldName(StructureUtils.YEAR_START); + jsonGenerator.writeStartObject(); + if (yearStart != null) { + jsonGenerator.writeNumberField(StructureUtils.DAY_OF_MONTH, yearStart.getDayOfMonth()); + jsonGenerator.writeNumberField(StructureUtils.MONTH_OF_YEAR, yearStart.getMonthOfYear()); + } + jsonGenerator.writeEndObject(); + } + + private void writeMappedFreq(JsonGenerator jsonGenerator, List mappedFrequencies) throws IOException { + if (mappedFrequencies != null) { + List freqIds = mappedFrequencies.stream() + .filter(Objects::nonNull) + .map(IdentifiableArtefact::getId) + .collect(Collectors.toList()); + jsonGenerator.writeFieldName(StructureUtils.MAPPED_FREQUENCIES); + jsonGenerator.writeStartArray(); + for (String id : freqIds) { + jsonGenerator.writeString(id); + } + jsonGenerator.writeEndArray(); + } + } + + private void writeMappedComponents(JsonGenerator jsonGenerator, List mappedComponents) throws IOException { + jsonGenerator.writeFieldName(StructureUtils.MAPPED_COMPONENTS); + jsonGenerator.writeStartArray(); + for (MappedComponent mappedComponent : mappedComponents) { + if (mappedComponent != null) { + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField(StructureUtils.SOURCE, mappedComponent.getSource()); + jsonGenerator.writeStringField(StructureUtils.TARGET, mappedComponent.getTarget()); + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + + private void writeFixedValueMaps(JsonGenerator jsonGenerator, List fixedComponentMaps) throws IOException { + if (fixedComponentMaps != null) { + jsonGenerator.writeFieldName(StructureUtils.FIXED_VALUE_MAPS); + jsonGenerator.writeStartArray(); + for (FixedValueMap fixedValueMap : fixedComponentMaps) { + if (fixedValueMap != null) { + jsonGenerator.writeStartObject(); + annotableWriter.write(jsonGenerator, fixedValueMap); + jsonGenerator.writeStringField(StructureUtils.VALUE, fixedValueMap.getValue()); + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } + + private void writeComponentMaps(JsonGenerator jsonGenerator, List componentMaps) throws IOException { + if (CollectionUtils.isNotEmpty(componentMaps)) { + jsonGenerator.writeFieldName(StructureUtils.COMPONENT_MAPS); + jsonGenerator.writeStartArray(); + for (ComponentMap map : componentMaps) { + if (map != null) { + jsonGenerator.writeStartObject(); + annotableWriter.write(jsonGenerator, map); + List sourceIds = map.getSource(); + writeSourcesTargets(sourceIds, jsonGenerator, StructureUtils.SOURCE); + + List targetIds = map.getTarget(); + writeSourcesTargets(targetIds, jsonGenerator, StructureUtils.TARGET); + + ArtefactReference representationMap = map.getRepresentationMap(); + if (representationMap != null) { + jsonGenerator.writeStringField(StructureUtils.REPRESENTATION_MAP, referenceAdapter.adaptUrn(representationMap.getUrn())); + } + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } + + private void writeSourcesTargets(List sourceOrTargetIds, JsonGenerator jsonGenerator, String sourceOrTargetName) throws IOException { + if (CollectionUtils.isNotEmpty(sourceOrTargetIds)) { + jsonGenerator.writeFieldName(sourceOrTargetName); + jsonGenerator.writeStartArray(); + for (String id : sourceOrTargetIds) { + jsonGenerator.writeString(id); + } + jsonGenerator.writeEndArray(); + } + } + + private void writeFrequencyFormatMappings(JsonGenerator jsonGenerator, List frequencyFormatMappings) throws IOException { + if (frequencyFormatMappings != null) { + jsonGenerator.writeFieldName(StructureUtils.FREQUENCY_FORMAT_MAPPINGS); + jsonGenerator.writeStartArray(); + for (FrequencyFormatMapping frequencyFormatMapping : frequencyFormatMappings) { + if (frequencyFormatMapping != null) { + jsonGenerator.writeStartObject(); + jsonGenerator.writeStringField(StructureUtils.FREQUENCY_ID, frequencyFormatMapping.getFrequencyCode()); + jsonGenerator.writeStringField(StructureUtils.DATE_PATTERN, frequencyFormatMapping.getDatePattern()); + identifiableWriter.write(jsonGenerator, frequencyFormatMapping); + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } + + private void writeDatePatternMaps(JsonGenerator jsonGenerator, Map> datePatternMaps) throws IOException { + if (datePatternMaps != null) { + jsonGenerator.writeFieldName(StructureUtils.DATE_PATTERN_MAPS); + jsonGenerator.writeStartArray(); + for (Map.Entry> map : datePatternMaps.entrySet()) { + jsonGenerator.writeStartObject(); + writeDateMap(jsonGenerator, map.getKey(), map.getValue()); + jsonGenerator.writeStringField(StructureUtils.LOCALE, map.getKey() + .getLocale()); + jsonGenerator.writeStringField(StructureUtils.SOURCE_PATTERN, map.getKey() + .getSourcePattern()); + jsonGenerator.writeEndObject(); + } + + jsonGenerator.writeEndArray(); + } + } + + private void writeEpochMaps(JsonGenerator jsonGenerator, Map> epochMaps) throws IOException { + if (epochMaps != null) { + jsonGenerator.writeFieldName(StructureUtils.EPOCH_MAPS); + jsonGenerator.writeStartArray(); + for (Map.Entry> map : epochMaps.entrySet()) { + jsonGenerator.writeStartObject(); + writeDateMap(jsonGenerator, map.getKey(), map.getValue()); + Instant basePeriod = map.getKey() + .getBasePeriod(); + if (basePeriod != null) { + jsonGenerator.writeStringField(StructureUtils.BASE_PERIOD, StructureUtils.mapInstantToString(basePeriod)); + } + EpochPeriodType epochPeriod = map.getKey() + .getEpochPeriod(); + if (epochPeriod != null) { + jsonGenerator.writeStringField(StructureUtils.EPOCH_PERIOD, epochPeriod.toString()); + } + jsonGenerator.writeEndObject(); + } + jsonGenerator.writeEndArray(); + } + } + + private void writeSource(JsonGenerator jsonGenerator, ArtefactReference source) throws IOException { + if (source != null) { + jsonGenerator.writeStringField(StructureUtils.SOURCE, referenceAdapter.toAdaptedUrn(source)); + } + } + + private void writeTarget(JsonGenerator jsonGenerator, ArtefactReference target) throws IOException { + if (target != null) { + jsonGenerator.writeStringField(StructureUtils.TARGET, referenceAdapter.toAdaptedUrn(target)); + } + } +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/StructureUtils.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/StructureUtils.java new file mode 100644 index 0000000..9a0d132 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/StructureUtils.java @@ -0,0 +1,446 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.CascadeValue; +import com.epam.jsdmx.infomodel.sdmx30.ConstraintRoleType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.infomodel.sdmx30.TextFormatImpl; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +import com.fasterxml.jackson.core.JsonGenerator; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections4.BidiMap; +import org.apache.commons.collections4.bidimap.DualHashBidiMap; +import org.apache.commons.lang3.StringUtils; + +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class StructureUtils { + + public static final String ID = "id"; + public static final String NAME = "name"; + public static final String NAMES = "names"; + public static final String VERSION = "version"; + public static final String AGENCY_ID = "agencyID"; + public static final String DESCRIPTION = "description"; + public static final String DESCRIPTIONS = "descriptions"; + public static final String VALID_TO = "validTo"; + public static final String VALID_FROM = "validFrom"; + + public static final String CATEGORIES = "categories"; + + public static final String ANNOTATIONS = "annotations"; + public static final String TITLE = "title"; + public static final String URL = "url"; + public static final String VALUE = "value"; + public static final String LANG = "lang"; + public static final String TEXT = "text"; + public static final String TEXTS = "texts"; + public static final String LINKS = "links"; + public static final String URN = "urn"; + public static final String TYPE = "type"; + public static final String REL = "rel"; + + public static final String IS_PARTIAL = "isPartial"; + + public static final String MAX_OCCURS = "maxOccurs"; + public static final String MIN_OCCURS = "minOccurs"; + public static final String CONCEPT_IDENTITY = "conceptIdentity"; + public static final String IS_PRESENTATIONAL = "isPresentational"; + public static final String LOCAL_REPRESENTATION = "localRepresentation"; + public static final String CORE_REPRESENTATION = "coreRepresentation"; + + public static final String SOURCE = "source"; + public static final String TARGET = "target"; + public static final String PREFIX = "prefix"; + public static final String SEQUENCE = "sequence"; + public static final String CODE_LIST = "codelist"; + + public static final String HAS_FORMAT_LEVELS = "hasFormalLevels"; + public static final String LEVEL = "level"; + + public static final String METADATA_ATTRIBUTE_USAGES = "metadataAttributeUsages"; + public static final String METADATA_ATTRIBUTE_REFERENCE = "metadataAttributeReference"; + public static final String ATTRIBUTE_LIST = "attributeList"; + public static final String DIMENSION_LIST = "dimensionList"; + public static final String DIMENSIONS = "dimensions"; + public static final String GROUP_DIMENSIONS = "groupDimensions"; + public static final String ATTRIBUTES = "attributes"; + public static final String TIME_DIMENSIONS = "timeDimensions"; + public static final String MEASURE_LIST = "measureList"; + public static final String MEASURES = "measures"; + public static final String MEASURE_RELATIONSHIP = "measureRelationship"; + public static final String ATTRIBUTE_RELATIONSHIP = "attributeRelationship"; + public static final String CONCEPT_ROLES = "conceptRoles"; + public static final String IS_MANDATORY = "isMandatory"; + public static final String POSITION = "position"; + public static final String METADATA = "metadata"; + public static final String DIMENSION = "dimension"; + public static final String OBSERVATION = "observation"; + public static final String NONE = "none"; + + public static final String METADATA_STRUCTURE_COMPONENTS = "metadataStructureComponents"; + public static final String METADATA_ATTRIBUTE_LIST = "metadataAttributeList"; + public static final String METADATA_ATTRIBUTES = "metadataAttributes"; + public static final String ENUMERATION = "enumeration"; + + public static final String IS_REG_EX = "isRegEx"; + public static final String SOURCE_VALUES = "sourceValues"; + public static final String TARGET_VALUES = "targetValues"; + public static final String REPRESENTATION_MAPPINGS = "representationMappings"; + public static final String START_INDEX = "startIndex"; + public static final String END_INDEX = "endIndex"; + public static final String DATA_TYPE = "dataType"; + public static final String EPOCH_MAPS = "epochMaps"; + public static final String BASE_PERIOD = "basePeriod"; + public static final String EPOCH_PERIOD = "epochPeriod"; + + public static final String CONCEPTS = "concepts"; + + public static final String CODE = "code"; + public static final String CODES = "codes"; + public static final String CODE_LIST_EXTENSIONS = "codelistExtensions"; + public static final String INCLUSIVE_CODE_SELECTION = "inclusiveCodeSelection"; + public static final String EXCLUSIVE_CODE_SELECTION = "exclusiveCodeSelection"; + public static final String MEMBER_VALUES = "memberValues"; + public static final String CASCADE_VALUES = "cascadeValues"; + public static final String WILDCARDED_MEMBER_VALUES = "wildcardedMemberValues"; + public static final String PARENT = "parent"; + public static final String STRUCTURE = "structure"; + + public static final String DATA_CONSTRAINTS = "dataConstraints"; + public static final String ROLE = "role"; + public static final String RELEASE_CALENDAR = "releaseCalendar"; + public static final String TOLERANCE = "tolerance"; + public static final String OFFSET = "offset"; + public static final String PERIODICITY = "periodicity"; + public static final String INCLUDE = "include"; + public static final String CONSTRAINT_ATTACHMENT = "constraintAttachment"; + public static final String DATA_PROVIDER = "dataProvider"; + public static final String PROVISION_AGREEMENTS = "provisionAgreements"; + public static final String DATA_KEY_SETS = "dataKeySets"; + public static final String KEYS = "keys"; + public static final String KEY_VALUES = "keyValues"; + public static final String REMOVE_PREFIX = "removePrefix"; + public static final String COMPONENTS = "components"; + public static final String VALUES = "values"; + public static final String TIME_RANGE = "timeRange"; + public static final String START_PERIOD = "startPeriod"; + public static final String END_PERIOD = "endPeriod"; + public static final String BEFORE_PERIOD = "beforePeriod"; + public static final String AFTER_PERIOD = "afterPeriod"; + public static final String PERIOD = "period"; + public static final String IS_INCLUSIVE = "isInclusive"; + public static final String CUBE_REGIONS = "cubeRegions"; + public static final String IS_INCLUDED = "isIncluded"; + + public static final String DATA_STRUCTURE_COMPONENTS = "dataStructureComponents"; + + public static final String HIERARCHICAL_CODES = "hierarchicalCodes"; + public static final String METADATA_FLOW = "metadataflow"; + public static final String TARGETS = "targets"; + public static final String FORMAT = "format"; + public static final String DECIMALS = "decimals"; + public static final String IS_MULTI_LINGUAL = "isMultiLingual"; + public static final String IS_SEQUENCE = "isSequence"; + public static final String INTERVAL = "interval"; + public static final String START_VALUE = "startValue"; + public static final String END_VALUE = "endValue"; + public static final String TIME_INTERVAL = "timeInterval"; + public static final String START_TIME = "startTime"; + public static final String END_TIME = "endTime"; + public static final String MIN_LENGTH = "minLength"; + public static final String MAX_LENGTH = "maxLength"; + public static final String MIN_VALUE = "minValue"; + public static final String MAX_VALUE = "maxValue"; + public static final String PATTERN = "pattern"; + + public static final String DATA = "data"; + public static final String CATEGORISATIONS = "categorisations"; + public static final String CATEGORY_SCHEMES = "categorySchemes"; + public static final String CODE_LISTS = "codelists"; + public static final String CONCEPT_SCHEMES = "conceptSchemes"; + public static final String DATA_STRUCTURES = "dataStructures"; + public static final String HIERARCHIES = "hierarchies"; + public static final String METADATAFLOWS = "metadataflows"; + public static final String METADATA_SETS = "metadataSets"; + public static final String METADATA_STRUCTURES = "metadataStructures"; + public static final String REPRESENTATION_MAPS = "representationMaps"; + public static final String DATAFLOWS = "dataflows"; + public static final String STRUCTURE_MAP = "structureMaps"; + public static final String DATE_PATTERN_MAPS = "datePatternMaps"; + public static final String LOCALE = "locale"; + public static final String SOURCE_PATTERN = "sourcePattern"; + public static final String COMPONENT_MAPS = "componentMaps"; + public static final String REPRESENTATION_MAP = "representationMap"; + public static final String FIXED_VALUE_MAPS = "fixedValueMaps"; + + public static final String FREQUENCY_FORMAT_MAPPINGS = "frequencyFormatMappings"; + public static final String FREQUENCY_ID = "frequencyId"; + public static final String DATE_PATTERN = "datePattern"; + public static final String RESOLVE_PERIOD = "resolvePeriod"; + public static final String FREQUENCY_DIMENSION = "frequencyDimension"; + public static final String YEAR_START = "yearStart"; + public static final String DAY_OF_MONTH = "dayOfMonth"; + public static final String MONTH_OF_YEAR = "monthOfYear"; + public static final String MAPPED_COMPONENTS = "mappedComponents"; + public static final String METADATA_PROVISION_AGREEMENT = "metadataProvisionAgreement"; + public static final String METADATA_PROVISION_AGREEMENTS = "metadataProvisionAgreements"; + public static final String ISOCONCEPTREFERENCE = "isoConceptReference"; + public static final String ENUMERATION_FORMAT = "enumerationFormat"; + public static final String CODING_FORMAT = "codingFormat"; + public static final String NO_SUCH_PROPERTY_IN = "no such property in "; + public static final String TARGET_FREQUENCY_ID = "targetFrequencyID"; + public static final String MAPPED_FREQUENCIES = "mappedFrequencies"; + public static final String SCHEMA = "schema"; + public static final String TEST = "test"; + public static final String PREPARED = "prepared"; + public static final String CONTENT_LANGUAGES = "contentLanguages"; + public static final String SENDER = "sender"; + public static final String IS_EXTERNAL_REFERENCE = "isExternalReference"; + public static final String META = "meta"; + public static final String GROUPS = "groups"; + public static final String TITLES = "titles"; + public static final String HREF = "href"; + public static final String HREFLANG = "hreflang"; + public static final String URI = "uri"; + public static final String BASIC_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; + public static final String ZONE = "Z"; + + public static final String CONTACTS = "contacts"; + public static final String DEPARTMENT = "department"; + public static final String TELEPHONES = "telephones"; + public static final String FAXES = "faxes"; + public static final String X_400_S = "x400s"; + public static final String URIS = "uris"; + public static final String EMAILS = "emails"; + public static final String AGENCIES = "agencies"; + public static final String AGENCIES_ID = "AGENCIES"; + public static final String DATA_CONSUMERS = "dataConsumers"; + public static final String DATA_PROVIDERS = "dataProviders"; + public static final String METADATA_PROVIDERS = "metadataProviders"; + public static final String VALUE_ITEMS = "valueItems"; + + public static final String LINKED_OBJECT = "linkedObject"; + public static final String LINKED_HIERARCHY = "linkedHierarchy"; + public static final String CONTEXT_OBJECT = "contextObject"; + public static final String ORGANISATION_UNITS = "organisationUnits"; + public static final String REPORTING_CATEGORIES = "reportingCategories"; + public static final String STRUCTURAL_METADATA = "structuralMetadata"; + public static final String PROVISIONING_METADATA = "provisioningMetadata"; + public static final String ITEM_MAPS = "itemMaps"; + public static final String SOURCE_VALUE = "sourceValue"; + public static final String TARGET_VALUE = "targetValue"; + public static final String DATAFLOW = "dataflow"; + public static final String METADATAFLOW = "metadataflow"; + public static final String METADATA_PROVIDER = "metadataProvider"; + public static final String CONDITION = "condition"; + public static final String CONDITIONS = "conditions"; + public static final String LOCAL_ID = "localID"; + public static final String TARGET_STEP = "targetStep"; + public static final String TRANSITIONS = "transitions"; + public static final String OBJECT_REFERENCE = "objectReference"; + public static final String SOFTWARE_LANGUAGE = "softwareLanguage"; + public static final String SOFTWARE_PACKAGE = "softwarePackage"; + public static final String SOFTWARE_VERSION = "softwareVersion"; + public static final String COMPUTATION = "computation"; + public static final String OUTPUTS = "outputs"; + public static final String INPUTS = "inputs"; + public static final String PROCESS_STEPS = "processSteps"; + public static final String METADATA_TARGET_REGIONS = "metadataTargetRegions"; + + public static final String SENTINEL_VALUES = "sentinelValues"; + public static final String ISO_CONCEPT_REFERENCE = "isoConceptReference"; + public static final String CONCEPT_SCHEME_ID = "conceptSchemeID"; + public static final String CONCEPT_ID = "conceptID"; + public static final String CONCEPT_AGENCY = "conceptAgency"; + public static final String GROUP = "group"; + public static final String AGENCY_SCHEMES = "agencySchemes"; + public static final String CATEGORY_SCHEME_MAPS = "categorySchemeMaps"; + public static final String CONCEPT_SCHEME_MAPS = "conceptSchemeMaps"; + public static final String DATA_CONSUMER_SCHEMES = "dataConsumerSchemes"; + public static final String DATA_PROVIDER_SCHEMES = "dataProviderSchemes"; + public static final String METADATA_PROVIDER_SCHEMES = "metadataProviderSchemes"; + public static final String HIERARCHY_ASSOCIATIONS = "hierarchyAssociations"; + public static final String METADATA_CONSTRAINTS = "metadataConstraints"; + public static final String ORGANISATION_SCHEME_MAPS = "organisationSchemeMaps"; + public static final String PROCESSES = "processes"; + public static final String REPORTING_TAXONOMIES = "reportingTaxonomies"; + public static final String REPORTING_TAXONOMY_MAPS = "reportingTaxonomyMaps"; + public static final String VALUE_LISTS = "valueLists"; + public static final String ORGANISATION_UNIT_SCHEMES = "organisationUnitSchemes"; + public static final String TRUE = "true"; + public static final String FALSE = "false"; + public static final String EXCLUDE_ROOT = "exclude_root"; + public static final String YEAR_PATTERN = "yyyy"; + public static final String YEAR_QUART_PATTERN = "yyyy-QQ"; + public static final String REGEX = "-"; + public static final String ATTRIBUTE_DESCRIPTOR_ID = "AttributeDescriptor"; + public static final String DIMENSION_DESCRIPTOR_ID = "DimensionDescriptor"; + public static final String MEASURE_DESCRIPTOR_ID = "MeasureDescriptor"; + + + public static final String DATA_CONSUMERS_ID = "DATA_CONSUMERS"; + public static final String DATA_PROVIDERS_ID = "DATA_PROVIDERS"; + public static final String DEFAULT_VERSION = "1.0"; + + public static final String GEOGRAPHIC_CODELISTS = "geographicCodelists"; + public static final String GEO_GRID_CODELISTS = "geoGridCodelists"; + public static final String GEO_TYPE = "geoType"; + public static final String GEOGRAPHIC_CODELIST = "GeographicCodelist"; + public static final String GEO_GRID_CODELIST = "GeoGridCodelist"; + public static final String GEO_FEATURE_SET_CODES = "geoFeatureSetCodes"; + public static final BidiMap CASCADE_VALUE_TYPE_STRING = new DualHashBidiMap<>(); + public static final BidiMap STRING_CASCADE_VALUE_TYPE = CASCADE_VALUE_TYPE_STRING.inverseBidiMap(); + public static final BidiMap CONSTRAINT_ROLE_STRING = new DualHashBidiMap<>(); + public static final BidiMap STRING_CONSTRAINT_ROLE = CONSTRAINT_ROLE_STRING.inverseBidiMap(); + + public static final String GRID_DEFINITION = "gridDefinition"; + public static final String GEO_GRID_CODES = "geoGridCodes"; + public static final String GEO_CELL = "geoCell"; + + static { + CASCADE_VALUE_TYPE_STRING.put(CascadeValue.TRUE, TRUE); + CASCADE_VALUE_TYPE_STRING.put(CascadeValue.FALSE, FALSE); + CASCADE_VALUE_TYPE_STRING.put(CascadeValue.EXCLUDE_ROOT, "excluderoot"); + } + + static { + CONSTRAINT_ROLE_STRING.put(ConstraintRoleType.ALLOWABLE_CONTENT, "Allowed"); + CONSTRAINT_ROLE_STRING.put(ConstraintRoleType.ACTUAL_CONTENT, "Actual"); + } + + public static void writeInternationalString(JsonGenerator jsonGenerator, + InternationalString string, + String fieldName) throws IOException { + if (string != null) { + jsonGenerator.writeFieldName(fieldName); + jsonGenerator.writeStartObject(); + string.getAllAsStream().forEach(entry -> { + final String text = entry.getValue(); + final String locale = entry.getKey(); + if (StringUtils.isNotEmpty(text)) { + try { + jsonGenerator.writeStringField(locale, text); + } catch (IOException e) { + log.error(e.getMessage()); + } + } + }); + + jsonGenerator.writeEndObject(); + } + } + + public static String mapInstantToString(Instant time) { + return time == null ? null : time.toString(); + } + + public static Optional getArtefactReferenceByStructureClass(List constrainedArtefacts, + StructureClassImpl structureClass) { + return constrainedArtefacts.stream() + .filter(Objects::nonNull) + .filter(reference -> reference.getStructureClass().equals(structureClass)) + .findAny(); + } + + public static List getArtefactReferencesByStructureClass(List constrainedArtefacts, + StructureClassImpl structureClass) { + return constrainedArtefacts.stream() + .filter(Objects::nonNull) + .filter(reference -> reference.getStructureClass().equals(structureClass)) + .collect(Collectors.toList()); + } + + public static void writeArtefactReferences(JsonGenerator jsonGenerator, + List references, + String refName, + ReferenceAdapter adapter) throws IOException { + if (CollectionUtils.isNotEmpty(references)) { + jsonGenerator.writeFieldName(refName); + jsonGenerator.writeStartArray(); + for (ArtefactReference reference : references) { + if (reference != null) { + jsonGenerator.writeString(adapter.toAdaptedUrn(reference)); + } + } + jsonGenerator.writeEndArray(); + } + } + + public static void writeCommonFormatAttributes(JsonGenerator jsonGenerator, TextFormatImpl textFormat) throws IOException { + Optional valueType = textFormat.getValueType(); + if (valueType.isPresent()) { + jsonGenerator.writeStringField(StructureUtils.DATA_TYPE, valueType.get().value()); + } + Optional sequence = textFormat.getIsSequence(); + if (sequence.isPresent()) { + jsonGenerator.writeBooleanField(StructureUtils.IS_SEQUENCE, sequence.get()); + } + Optional interval = textFormat.getInterval(); + if (interval.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.INTERVAL, interval.get()); + } + Optional startValue = textFormat.getStartValue(); + if (startValue.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.START_VALUE, startValue.get()); + } + Optional endValue = textFormat.getEndValue(); + if (endValue.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.END_VALUE, endValue.get()); + } + Optional timeInterval = textFormat.getTimeInterval(); + if (timeInterval.isPresent()) { + jsonGenerator.writeStringField(StructureUtils.TIME_INTERVAL, timeInterval.get()); + } + Optional startTime = textFormat.getStartTime(); + if (startTime.isPresent()) { + jsonGenerator.writeStringField(StructureUtils.START_TIME, startTime.get().toString()); + } + Optional endTime = textFormat.getEndTime(); + if (endTime.isPresent()) { + jsonGenerator.writeStringField(StructureUtils.END_TIME, endTime.get().toString()); + } + Optional minLength = textFormat.getMinLength(); + if (minLength.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.MIN_LENGTH, minLength.get()); + } + Optional maxLength = textFormat.getMaxLength(); + if (maxLength.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.MAX_LENGTH, maxLength.get()); + } + Optional minValue = textFormat.getMinValue(); + if (minValue.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.MIN_VALUE, minValue.get()); + } + Optional maxValue = textFormat.getMaxValue(); + if (maxValue.isPresent()) { + jsonGenerator.writeNumberField(StructureUtils.MAX_VALUE, maxValue.get()); + } + Optional pattern = textFormat.getPattern(); + if (pattern.isPresent()) { + jsonGenerator.writeStringField(StructureUtils.PATTERN, pattern.get()); + } + } + + public static String getLocalisedValue(InternationalString i18nString, List languagePriorities) { + final String prioritised = i18nString.getForRanges(languagePriorities); + return StringUtils.isNotEmpty(prioritised) ? prioritised : i18nString.getForDefaultLocale(); + } + +} diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ValueListWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ValueListWriter.java new file mode 100644 index 0000000..48bae9d --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/ValueListWriter.java @@ -0,0 +1,83 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.ValueItem; +import com.epam.jsdmx.infomodel.sdmx30.ValueList; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.collections.CollectionUtils; + +public class ValueListWriter extends MaintainableWriter { + + private final AnnotableWriter annotableWriter; + + public ValueListWriter(VersionableWriter versionableWriter, + LinksWriter linksWriter, + AnnotableWriter annotableWriter) { + super(versionableWriter, linksWriter); + this.annotableWriter = annotableWriter; + } + + @Override + protected void writeFields(JsonGenerator jsonGenerator, ValueList artefact) throws IOException { + super.writeFields(jsonGenerator, artefact); + List items = artefact.getItems(); + if (CollectionUtils.isNotEmpty(items)) { + jsonGenerator.writeFieldName(StructureUtils.VALUE_ITEMS); + jsonGenerator.writeStartArray(); + + for (ValueItem valueItem : items) { + if (valueItem != null) { + jsonGenerator.writeStartObject(); + annotableWriter.write(jsonGenerator, valueItem); + + String id = valueItem.getId(); + if (id != null) { + jsonGenerator.writeStringField(StructureUtils.ID, id); + } + + InternationalString name = valueItem.getName(); + writeName(jsonGenerator, artefact, name); + + InternationalString description = valueItem.getDescription(); + writeDescription(jsonGenerator, description); + + jsonGenerator.writeEndObject(); + } + } + jsonGenerator.writeEndArray(); + } + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getValueLists(); + } + + @Override + protected String getArrayName() { + return StructureUtils.VALUE_LISTS; + } + + private void writeDescription(JsonGenerator jsonGenerator, InternationalString description) throws IOException { + if (description != null) { + jsonGenerator.writeStringField( + StructureUtils.DESCRIPTION, + description.getForDefaultLocale() + ); + StructureUtils.writeInternationalString(jsonGenerator, description, StructureUtils.DESCRIPTIONS); + } + } + + private void writeName(JsonGenerator jsonGenerator, ValueList artefact, InternationalString name) throws IOException { + if (name != null) { + jsonGenerator.writeStringField(StructureUtils.NAME, artefact.getName().getForDefaultLocale()); + StructureUtils.writeInternationalString(jsonGenerator, name, StructureUtils.NAMES); + } + } +} \ No newline at end of file diff --git a/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/VersionableWriter.java b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/VersionableWriter.java new file mode 100644 index 0000000..b2797f7 --- /dev/null +++ b/sdmx-json20/src/main/java/com/epam/jsdmx/json20/structure/writer/VersionableWriter.java @@ -0,0 +1,29 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.VersionableArtefact; + +import com.fasterxml.jackson.core.JsonGenerator; + +public class VersionableWriter { + + private final NameableWriter nameableWriter; + + public VersionableWriter(NameableWriter nameableWriter) { + this.nameableWriter = nameableWriter; + } + + public void write(JsonGenerator jsonGenerator, VersionableArtefact artefact) throws IOException { + nameableWriter.write(jsonGenerator, artefact); + jsonGenerator.writeStringField(StructureUtils.VERSION, artefact.getVersion().toString()); + String validTo = artefact.getValidToString(); + if (validTo != null) { + jsonGenerator.writeStringField(StructureUtils.VALID_TO, validTo); + } + String validFrom = artefact.getValidFromString(); + if (validFrom != null) { + jsonGenerator.writeStringField(StructureUtils.VALID_FROM, validFrom); + } + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/MaintainableArtifactsTestUtils.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/MaintainableArtifactsTestUtils.java new file mode 100644 index 0000000..518e5bb --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/MaintainableArtifactsTestUtils.java @@ -0,0 +1,1776 @@ +package com.epam.jsdmx.json20.structure; + +import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; + +import java.io.ByteArrayOutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.AfterPeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.AgencyImpl; +import com.epam.jsdmx.infomodel.sdmx30.AgencySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Annotation; +import com.epam.jsdmx.infomodel.sdmx30.AnnotationImpl; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseFacetImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseTextFormatRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.BeforePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.CascadeValue; +import com.epam.jsdmx.infomodel.sdmx30.CategorisationImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategoryImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodingFormat; +import com.epam.jsdmx.infomodel.sdmx30.CodingFormatImpl; +import com.epam.jsdmx.infomodel.sdmx30.ComponentMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.ComponentValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.ComputationImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConstraintRoleType; +import com.epam.jsdmx.infomodel.sdmx30.Contact; +import com.epam.jsdmx.infomodel.sdmx30.ContactImpl; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegion; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionImpl; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionKeyImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataKeyImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySet; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySetImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.DatePatternMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponentImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.EnumeratedRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.EpochMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.EpochPeriodType; +import com.epam.jsdmx.infomodel.sdmx30.ExclusiveCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.Facet; +import com.epam.jsdmx.infomodel.sdmx30.FacetType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueTypeRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.FixedValueMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.FrequencyFormatMappingImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCode; +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeoGridCodelist; +import com.epam.jsdmx.infomodel.sdmx30.GeoGridCodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeographicCodelist; +import com.epam.jsdmx.infomodel.sdmx30.GeographicCodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.GridCode; +import com.epam.jsdmx.infomodel.sdmx30.GridCodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.GroupDimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.GroupRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchicalCodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyAssociation; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyAssociationImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableObjectSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.InclusiveCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.IsoConceptReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.infomodel.sdmx30.ItemMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.LevelImpl; +import com.epam.jsdmx.infomodel.sdmx30.ListReferenceValueRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.LocalisedMemberValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.MappedValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.MappingRoleType; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeRefImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderScheme; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProvisionAgreement; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProvisionAgreementImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataTargetRegion; +import com.epam.jsdmx.infomodel.sdmx30.MetadataTargetRegionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.ObservationRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationSchemeMap; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationSchemeMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitImpl; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitScheme; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.infomodel.sdmx30.Process; +import com.epam.jsdmx.infomodel.sdmx30.ProcessArtefactImpl; +import com.epam.jsdmx.infomodel.sdmx30.ProcessImpl; +import com.epam.jsdmx.infomodel.sdmx30.ProcessStep; +import com.epam.jsdmx.infomodel.sdmx30.ProcessStepImpl; +import com.epam.jsdmx.infomodel.sdmx30.ProvisionAgreement; +import com.epam.jsdmx.infomodel.sdmx30.ProvisionAgreementImpl; +import com.epam.jsdmx.infomodel.sdmx30.RangePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendar; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendarImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReportingCategoryImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomy; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyMap; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMappingImpl; +import com.epam.jsdmx.infomodel.sdmx30.ResolvePeriod; +import com.epam.jsdmx.infomodel.sdmx30.SentinelValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.TargetValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.TimeDimensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.TimeRangePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.TransitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.ValueItemImpl; +import com.epam.jsdmx.infomodel.sdmx30.ValueList; +import com.epam.jsdmx.infomodel.sdmx30.ValueListImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; +import com.epam.jsdmx.json20.structure.reader.AnnotableReader; +import com.epam.jsdmx.json20.structure.reader.CategorisationReader; +import com.epam.jsdmx.json20.structure.reader.CategorySchemeReader; +import com.epam.jsdmx.json20.structure.reader.CodeImplReader; +import com.epam.jsdmx.json20.structure.reader.CodelistExtensionReader; +import com.epam.jsdmx.json20.structure.reader.CodelistReader; +import com.epam.jsdmx.json20.structure.reader.ConceptSchemeReader; +import com.epam.jsdmx.json20.structure.reader.ContactReader; +import com.epam.jsdmx.json20.structure.reader.CubeRegionReader; +import com.epam.jsdmx.json20.structure.reader.DataConstraintReader; +import com.epam.jsdmx.json20.structure.reader.DataFlowReader; +import com.epam.jsdmx.json20.structure.reader.DataKeySetReader; +import com.epam.jsdmx.json20.structure.reader.DataReader; +import com.epam.jsdmx.json20.structure.reader.DataStructureDefinitionReader; +import com.epam.jsdmx.json20.structure.reader.HierarchyReader; +import com.epam.jsdmx.json20.structure.reader.IdentifiableReader; +import com.epam.jsdmx.json20.structure.reader.JsonStructureReader; +import com.epam.jsdmx.json20.structure.reader.MemberSelectionReader; +import com.epam.jsdmx.json20.structure.reader.MetaDataStructureDefinitionReader; +import com.epam.jsdmx.json20.structure.reader.MetaReader; +import com.epam.jsdmx.json20.structure.reader.MetadataFlowReader; +import com.epam.jsdmx.json20.structure.reader.NameableReader; +import com.epam.jsdmx.json20.structure.reader.OrganisationReader; +import com.epam.jsdmx.json20.structure.reader.ReleaseCalendarReader; +import com.epam.jsdmx.json20.structure.reader.RepresentationMapReader; +import com.epam.jsdmx.json20.structure.reader.StructureMapReader; +import com.epam.jsdmx.json20.structure.reader.VersionableReader; +import com.epam.jsdmx.json20.structure.writer.AnnotableWriter; +import com.epam.jsdmx.json20.structure.writer.AttributeListWriter; +import com.epam.jsdmx.json20.structure.writer.CategorisationWriter; +import com.epam.jsdmx.json20.structure.writer.CategorySchemeWriter; +import com.epam.jsdmx.json20.structure.writer.CodeWriterImpl; +import com.epam.jsdmx.json20.structure.writer.CodelistExtensionWriter; +import com.epam.jsdmx.json20.structure.writer.CodelistWriter; +import com.epam.jsdmx.json20.structure.writer.ComponentWriter; +import com.epam.jsdmx.json20.structure.writer.ConceptRoleWriter; +import com.epam.jsdmx.json20.structure.writer.ConceptSchemeWriter; +import com.epam.jsdmx.json20.structure.writer.ContactsWriter; +import com.epam.jsdmx.json20.structure.writer.CubeRegionWriter; +import com.epam.jsdmx.json20.structure.writer.DataConstraintWriter; +import com.epam.jsdmx.json20.structure.writer.DataKeySetsWriter; +import com.epam.jsdmx.json20.structure.writer.DataStructureDefinitionWriter; +import com.epam.jsdmx.json20.structure.writer.DataflowWriter; +import com.epam.jsdmx.json20.structure.writer.DateTimeWriter; +import com.epam.jsdmx.json20.structure.writer.DimensionListWriter; +import com.epam.jsdmx.json20.structure.writer.GroupDimensionListWriter; +import com.epam.jsdmx.json20.structure.writer.HierarchyWriter; +import com.epam.jsdmx.json20.structure.writer.IdentifiableWriter; +import com.epam.jsdmx.json20.structure.writer.JsonStructureWriter; +import com.epam.jsdmx.json20.structure.writer.LinksWriter; +import com.epam.jsdmx.json20.structure.writer.MeasureListWriter; +import com.epam.jsdmx.json20.structure.writer.MemberSelectionWriter; +import com.epam.jsdmx.json20.structure.writer.MetaWriter; +import com.epam.jsdmx.json20.structure.writer.MetadataStructureDefinitionWriter; +import com.epam.jsdmx.json20.structure.writer.MetadataflowWriter; +import com.epam.jsdmx.json20.structure.writer.NameableWriter; +import com.epam.jsdmx.json20.structure.writer.OrganisationWriter; +import com.epam.jsdmx.json20.structure.writer.RepresentationMapWriter; +import com.epam.jsdmx.json20.structure.writer.RepresentationWriter; +import com.epam.jsdmx.json20.structure.writer.StructureMapWriter; +import com.epam.jsdmx.json20.structure.writer.VersionableWriter; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; +import com.epam.jsdmx.serializer.common.StubDataStructureLocalRepresentationAdapter; +import com.epam.jsdmx.serializer.common.TimeDimensionLocalRepresentationAdapter; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultHeaderProvider; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultReferenceAdapter; +import com.epam.jsdmx.serializer.sdmx30.common.Header; +import com.epam.jsdmx.serializer.sdmx30.structure.StructureReader; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public final class MaintainableArtifactsTestUtils { + + /** + * sets common fields for maintainable artefact + * + * @param artefact - artefact to set fields for + */ + public static void setMaintainableArtefact(MaintainableArtefactImpl artefact) { + artefact.setId("ARTEFACT"); + artefact.setVersion(Version.createFromString("1.2")); + artefact.setOrganizationId("IMF"); + artefact.setName(new InternationalString("Maintanable artefact")); + artefact.getName().add(Locale.CANADA_FRENCH.toLanguageTag(), "artefact"); + String date = "2022-07-17T10:11:16Z"; + + artefact.setValidTo(date); + artefact.setValidFrom(date); + artefact.setDescription(new InternationalString("Some artefact")); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("1"); + annotation.setText(new InternationalString("text")); + annotation.setType("type1"); + artefact.addAnnotation(annotation); + } + + /** + * @return Categorisation object + */ + public static CategorisationImpl buildCategorisation() { + CategorisationImpl categorisation = new CategorisationImpl(); + setMaintainableArtefact(categorisation); + IdentifiableArtefactReferenceImpl structureItemReference = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.CATEGORY, + "CAT_TARGET" + ); + + categorisation.setCategorizedBy(structureItemReference); + IdentifiableArtefactReferenceImpl structureReference = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.CATEGORISATION, + "CAT_SOURCE" + ); + categorisation.setCategorizedArtefact(structureReference); + return categorisation; + } + + /** + * @return CategoryScheme object + */ + public static CategorySchemeImpl buildCategoryScheme() { + CategorySchemeImpl categoryScheme = new CategorySchemeImpl(); + setMaintainableArtefact(categoryScheme); + categoryScheme.setPartial(true); + CategoryImpl category = new CategoryImpl(); + category.setDescription(new InternationalString("description")); + category.setId("Category-1"); + category.setName(new InternationalString("Category1")); + category.setDescription(new InternationalString("description category 1")); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot"); + category.setAnnotations(List.of(annotation)); + CategoryImpl category2 = new CategoryImpl(); + category2.setDescription(new InternationalString("description category2")); + category2.setId("Category-2"); + category2.setName(new InternationalString("Category2")); + AnnotationImpl annotation2 = new AnnotationImpl(); + annotation2.setId("Annot2"); + category2.setAnnotations(List.of(annotation, annotation2)); + CategoryImpl category3 = new CategoryImpl(); + category3.setDescription(new InternationalString("description category3")); + category3.setId("Category-3"); + category3.setName(new InternationalString("Category3")); + category.setHierarchy(List.of(category2, category3)); + + CategoryImpl category4 = new CategoryImpl(); + category4.setId("Category-4"); + category4.setName(new InternationalString("Category4")); + categoryScheme.setItems(List.of(category, category4)); + return categoryScheme; + } + + /** + * @return Codelist object + */ + public static CodelistImpl buildCodeList() { + CodelistImpl codelist = new CodelistImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(codelist); + codelist.setPartial(true); + codelist.setExtensions(getExtensions()); + fillCodes(codelist); + return codelist; + } + + private static void fillCodes(CodelistImpl codelist) { + CodeImpl code = new CodeImpl(); + code.setDescription(new InternationalString("code 1 desc")); + code.setId("CODE1"); + code.setName(new InternationalString("code 1")); + code.setParentId("CODE2"); + CodeImpl code2 = new CodeImpl(); + code2.setDescription(new InternationalString("code 2 desc")); + code2.setId("CODE2"); + code2.setName(new InternationalString("code 2")); + codelist.setItems(List.of(code, code2)); + } + + private static List getExtensions() { + CodelistExtensionImpl inclusiveCodeListExtension = fillInclusiveCodeListExtension(); + CodelistExtensionImpl exclusiveCodeListExtension = fillExclusiveCodeListExtension(); + return List.of(inclusiveCodeListExtension, exclusiveCodeListExtension); + } + + private static CodelistExtensionImpl fillExclusiveCodeListExtension() { + CodelistExtensionImpl codelistExtension = new CodelistExtensionImpl(); + ExclusiveCodeSelectionImpl exclusiveCodeSelection = new ExclusiveCodeSelectionImpl(); + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setCascadeValue(CascadeValue.FALSE); + memberValue.setValue("mem2"); + exclusiveCodeSelection.setMembers(List.of(memberValue)); + return fillCodeListExtension(codelistExtension, exclusiveCodeSelection); + } + + private static CodelistExtensionImpl fillInclusiveCodeListExtension() { + CodelistExtensionImpl codelistExtension = new CodelistExtensionImpl(); + InclusiveCodeSelectionImpl inclusiveCodeSelection = new InclusiveCodeSelectionImpl(); + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setCascadeValue(CascadeValue.TRUE); + memberValue.setValue("mem1"); + inclusiveCodeSelection.setMembers(List.of(memberValue)); + return fillCodeListExtension(codelistExtension, inclusiveCodeSelection); + } + + private static CodelistExtensionImpl fillCodeListExtension(CodelistExtensionImpl codelistExtension, BaseCodeSelectionImpl codeSelection) { + codelistExtension.setPrefix("PREF2"); + MaintainableArtefactReference maintainableReference = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)"); + codelistExtension.setCodelist(maintainableReference); + codelistExtension.setCodeSelection(codeSelection); + return codelistExtension; + } + + /** + * @return ConceptScheme object + */ + public static ConceptSchemeImpl buildConceptScheme() { + ConceptSchemeImpl conceptScheme = new ConceptSchemeImpl(); + setMaintainableArtefact(conceptScheme); + ConceptImpl concept = new ConceptImpl(); + concept.setId("COUNTRY"); + concept.setName(new InternationalString("Country")); + IsoConceptReferenceImpl isoConceptReference = new IsoConceptReferenceImpl(); + isoConceptReference.setConceptId("Conn"); + isoConceptReference.setAgency("QHB"); + isoConceptReference.setSchemeId("Schema"); + concept.setIsoConceptReference(isoConceptReference); + concept.setCoreRepresentation(getRepresentation()); + conceptScheme.setItems(List.of(concept)); + conceptScheme.setPartial(true); + return conceptScheme; + } + + private static Representation getRepresentation() { + Set facetSet = new HashSet<>(); + BaseFacetImpl facet1 = new BaseFacetImpl(); + BaseFacetImpl facet2 = new BaseFacetImpl(); + facet1.setValueType(FacetValueType.ALPHA); + SentinelValueImpl sentinelValue = new SentinelValueImpl(); + sentinelValue.setValue("val"); + sentinelValue.setName(new InternationalString("sent")); + sentinelValue.setDescription(new InternationalString("sentinel descr")); + facet2.setSentinelValues(List.of(sentinelValue)); + facet2.setType(FacetType.SENTINEL_VALUES); + facet2.setValueType(FacetValueType.ALPHA); + facetSet.addAll(List.of(facet1, facet2)); + return new BaseTextFormatRepresentationImpl(facetSet); + } + + /** + * @return DataConstraint object + */ + public static DataConstraintImpl buildDataConstraint() { + DataConstraintImpl dataConstraint = new DataConstraintImpl(); + setMaintainableArtefact(dataConstraint); + dataConstraint.setConstraintRoleType(ConstraintRoleType.ALLOWABLE_CONTENT); + + dataConstraint.setCubeRegions(List.of(createCubeRegion())); + dataConstraint.setReleaseCalendar(createReleaseCalendar()); + dataConstraint.setDataContentKeys(List.of(createDataKeySets())); + dataConstraint.setConstrainedArtefacts(List.of(buildProvisionAgreement().getDataProvider())); + + return dataConstraint; + } + + /** + * @return DataStructureDefinition object + */ + public static DataStructureDefinitionImpl buildDataStructureDefinition() { + DataStructureDefinitionImpl dataStructureDefinition = new DataStructureDefinitionImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(dataStructureDefinition); + MaintainableArtefactReference maintainableReference = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)"); + dataStructureDefinition.setMetadataStructure(maintainableReference); + return dataStructureDefinition; + } + + /** + * @return MetadataStructureDefinition object + */ + public static MetadataStructureDefinitionImpl buildMetadataStructureDefinition() { + MetadataStructureDefinitionImpl metadataStructureDefinition = new MetadataStructureDefinitionImpl(); + setMaintainableArtefact(metadataStructureDefinition); + MetadataAttributeDescriptorImpl metadataAttributeDescriptor = new MetadataAttributeDescriptorImpl(); + metadataAttributeDescriptor.setId("MetadataAttributeDescriptor"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot-1"); + MetadataAttributeImpl metadataAttribute = getMetadataAttribute("meta-1", "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)"); + metadataAttribute.setHierarchy(List.of(getMetadataAttribute("meta-2", "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)"))); + metadataAttributeDescriptor.setComponents(List.of(metadataAttribute)); + metadataAttributeDescriptor.addAnnotation(annotation); + metadataStructureDefinition.setAttributeDescriptor(metadataAttributeDescriptor); + return metadataStructureDefinition; + } + + private static MetadataAttributeImpl getMetadataAttribute(String id, String reference) { + MetadataAttributeImpl metadataAttribute = new MetadataAttributeImpl(); + metadataAttribute.setId(id); + metadataAttribute.setMaxOccurs(20); + metadataAttribute.setMinOccurs(10); + metadataAttribute.setPresentational(true); + Representation representation = new EnumeratedRepresentationImpl( + new MaintainableArtefactReference(reference)); + metadataAttribute.setLocalRepresentation(representation); + metadataAttribute.setConceptIdentity( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DIM")); + return metadataAttribute; + } + + /** + * @return AttributeDescriptor + */ + public static AttributeDescriptorImpl fillAttributeDescriptor() { + AttributeDescriptorImpl attributeDescriptor = new AttributeDescriptorImpl(); + attributeDescriptor.setId("AttributeDescriptor"); + fillMetadata(attributeDescriptor); + fillComponents(attributeDescriptor); + return attributeDescriptor; + } + + + private static void fillComponents(AttributeDescriptorImpl attributeDescriptor) { + DataAttributeImpl dataAttribute = new DataAttributeImpl(); + dataAttribute.setId("DA1"); + dataAttribute.setMinOccurs(0); + dataAttribute.setMaxOccurs(1); + GroupRelationshipImpl groupRelationship = new GroupRelationshipImpl(); + groupRelationship.setGroupKey("GroupKey"); + dataAttribute.setAttributeRelationship(groupRelationship); + + final var typeFacet = new BaseFacetImpl(); + typeFacet.setValueType(FacetValueType.ALPHA_NUMERIC); + final var multilingualFacet = new BaseFacetImpl(); + multilingualFacet.setType(FacetType.IS_MULTILINGUAL); + multilingualFacet.setValue("false"); + + dataAttribute.setLocalRepresentation(new BaseTextFormatRepresentationImpl(Set.of(typeFacet, multilingualFacet))); + dataAttribute.setConceptIdentity(new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE")); + dataAttribute.setConceptRoles( + List.of( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE"), + new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE") + )); + MeasureRelationshipImpl measureRelationship = new MeasureRelationshipImpl(); + measureRelationship.setMeasures(List.of("MO")); + dataAttribute.setMeasureRelationship(measureRelationship); + attributeDescriptor.setComponents(List.of(dataAttribute)); + } + + private static void fillMetadata(AttributeDescriptorImpl attributeDescriptor) { + MetadataAttributeRefImpl attributeRef1 = new MetadataAttributeRefImpl(); + attributeRef1.setId("REFERENCE-1"); + attributeRef1.setMetadataRelationship(new ObservationRelationshipImpl()); + MetadataAttributeRefImpl attributeRef2 = new MetadataAttributeRefImpl(); + attributeRef2.setId("REFERENCE-2"); + DimensionRelationshipImpl dimensionRelationship = new DimensionRelationshipImpl(); + dimensionRelationship.setDimensions(List.of("dim1", "dim2")); + attributeRef2.setMetadataRelationship(dimensionRelationship); + MetadataAttributeRefImpl attributeRef3 = new MetadataAttributeRefImpl(); + attributeRef3.setId("REFERENCE-3"); + attributeRef3.setMetadataRelationship(null); + attributeDescriptor.setMetadataAttributes(List.of(attributeRef1, attributeRef2, attributeRef3)); + } + + /** + * @return List + */ + public static List fillListGroupDimensionDescriptor() { + GroupDimensionDescriptorImpl groupDimensionDescriptor1 = new GroupDimensionDescriptorImpl(); + AnnotationImpl annotation1 = new AnnotationImpl(); + annotation1.setId("id1"); + annotation1.setValue("val"); + AnnotationImpl annotation2 = new AnnotationImpl(); + annotation2.setId("id2"); + annotation2.setValue("val"); + groupDimensionDescriptor1.setId("GroupDimensionDescriptor1"); + groupDimensionDescriptor1.setAnnotations(List.of(annotation1, annotation2)); + groupDimensionDescriptor1.setDimensions(List.of("dim1", "dim12")); + + GroupDimensionDescriptorImpl groupDimensionDescriptor2 = new GroupDimensionDescriptorImpl(); + groupDimensionDescriptor2.setId("GroupDimensionDescriptor2"); + groupDimensionDescriptor2.setDimensions(List.of("dim21", "dim22")); + + return List.of(groupDimensionDescriptor1, groupDimensionDescriptor2); + } + + /** + * @return DimensionDescriptor + */ + public static DimensionDescriptorImpl fillDimensionDescriptor() { + DimensionDescriptorImpl dimensionDescriptor = new DimensionDescriptorImpl(); + dimensionDescriptor.setId("DimensionDescriptor"); + fillDimensionComponents(dimensionDescriptor); + return dimensionDescriptor; + } + + private static void fillDimensionComponents(DimensionDescriptorImpl dimensionDescriptor) { + DimensionImpl dimensionComponent = new DimensionImpl(); + dimensionComponent.setOrder(1); + dimensionComponent.setId("DIM1"); + dimensionComponent.setConceptRoles(List.of(new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE"))); + EnumeratedRepresentationImpl enumeratedRepresentation = new EnumeratedRepresentationImpl( + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)")); + dimensionComponent.setLocalRepresentation(enumeratedRepresentation); + dimensionComponent.setConceptIdentity( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE")); + DimensionComponentImpl dimensionTimeComponent = new TimeDimensionImpl(); + dimensionTimeComponent.setId("TIME_PERIOD"); + dimensionTimeComponent.setOrder(2); + dimensionTimeComponent.setConceptIdentity( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE")); + BaseFacetImpl baseFacet = new BaseFacetImpl(); + baseFacet.setValueType(FacetValueType.BASIC_TIME_PERIOD); + dimensionTimeComponent.setLocalRepresentation(new BaseTextFormatRepresentationImpl(Set.of(baseFacet))); + dimensionDescriptor.setComponents(List.of(dimensionComponent, dimensionTimeComponent)); + } + + /** + * @return MeasureDescriptor + */ + public static MeasureDescriptorImpl fillMeasureDescriptor() { + MeasureDescriptorImpl measureDescriptor = new MeasureDescriptorImpl(); + measureDescriptor.setId("MeasureDescriptor"); + fillMeasureComponents(measureDescriptor); + return measureDescriptor; + } + + private static void fillMeasureComponents(MeasureDescriptorImpl measureDescriptor) { + MeasureImpl measure = new MeasureImpl(); + measure.setId("MES1"); + measure.setConceptIdentity(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE")); + measure.setConceptRoles( + List.of( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE"), + new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE") + )); + final var baseFacet = new BaseFacetImpl(); + baseFacet.setValueType(FacetValueType.BASIC_TIME_PERIOD); + + final var multilingualFacet = new BaseFacetImpl(); + multilingualFacet.setType(FacetType.IS_MULTILINGUAL); + multilingualFacet.setValue("false"); + + measure.setLocalRepresentation(new BaseTextFormatRepresentationImpl(Set.of(baseFacet, multilingualFacet))); + measureDescriptor.setComponents(List.of(measure)); + } + + /** + * @return Hierarchy object + */ + public static HierarchyImpl buildHierarchy() { + HierarchyImpl hierarchy = new HierarchyImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(hierarchy); + hierarchy.setHasFormalLevels(true); + HierarchicalCodeImpl code = new HierarchicalCodeImpl(); + code.setId("id"); + code.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1")); + code.setLevelId("Lev1"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("id"); + code.setAnnotations(List.of(annotation)); + String dateStr = "2022-07-17T10:11:16.345Z"; + code.setValidTo(Instant.parse(dateStr)); + code.setValidFrom(Instant.parse(dateStr)); + HierarchicalCodeImpl code2 = new HierarchicalCodeImpl(); + code2.setId("hi-2"); + code2.setLevelId("Lev2"); + code2.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL2")); + code2.setValidTo(Instant.parse(dateStr)); + code2.setValidFrom(Instant.parse(dateStr)); + hierarchy.setCodes(List.of(code, code2)); + LevelImpl level = new LevelImpl(); + level.setDescription(new InternationalString("hierarchy desc")); + level.setName(new InternationalString("hierarchy name")); + level.setId("levId"); + level.setCodeFormat(List.of(fillListOfCodingFormats().get(0))); + hierarchy.setLevel(level); + return hierarchy; + } + + public static HierarchyImpl buildHierarchyWithInnerHierarchy() { + HierarchyImpl hierarchy = new HierarchyImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(hierarchy); + hierarchy.setHasFormalLevels(true); + HierarchicalCodeImpl code = new HierarchicalCodeImpl(); + code.setId("id"); + code.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1")); + code.setLevelId("Lev1"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("id"); + code.setAnnotations(List.of(annotation)); + String dateStr = "2022-07-17T10:11:16.345Z"; + code.setValidTo(Instant.parse(dateStr)); + code.setValidFrom(Instant.parse(dateStr)); + HierarchicalCodeImpl hierarchicalCode = new HierarchicalCodeImpl(); + hierarchicalCode.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1")); + hierarchicalCode.setId("1"); + hierarchicalCode.setValidTo(Instant.parse(dateStr)); + hierarchicalCode.setValidFrom(Instant.parse(dateStr)); + code.setHierarchicalCodes(List.of(hierarchicalCode)); + hierarchy.setCodes(List.of(code)); + LevelImpl level = new LevelImpl(); + level.setDescription(new InternationalString("hierarchy desc")); + level.setName(new InternationalString("hierarchy name")); + level.setId("levId"); + level.setCodeFormat(List.of(fillListOfCodingFormats().get(0))); + hierarchy.setLevel(level); + LevelImpl levelUn = new LevelImpl(); + levelUn.setId("levUn"); + levelUn.setName(new InternationalString("underLevel")); + level.setChild(levelUn); + return hierarchy; + } + + private static List fillListOfCodingFormats() { + List codingFormatList = new ArrayList<>(); + codingFormatList.add(addCodingFormat(FacetType.INTERVAL, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.IS_SEQUENCE, String.valueOf(true))); + codingFormatList.add(addCodingFormat(FacetType.MAX_LENGTH, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.MIN_LENGTH, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.MAX_VALUE, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.MIN_VALUE, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.PATTERN, "a")); + codingFormatList.add(addCodingFormat(FacetType.START_VALUE, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.END_VALUE, String.valueOf(1))); + + CodingFormatImpl codingFormat = new CodingFormatImpl(); + codingFormat.setCodingFormat(new BaseFacetImpl(FacetValueType.fromValue("Alpha"))); + codingFormatList.add(codingFormat); + return codingFormatList; + } + + private static CodingFormat addCodingFormat(FacetType facetType, String value) { + CodingFormatImpl codingFormat = new CodingFormatImpl(); + BaseFacetImpl baseFacet = new BaseFacetImpl(); + baseFacet.setType(facetType); + baseFacet.setValue(value); + codingFormat.setCodingFormat(baseFacet); + return codingFormat; + } + + /** + * @return Metadataflow object + */ + public static MetadataflowImpl buildMetadataFlow() { + MetadataflowImpl metadataflow = new MetadataflowImpl(); + setMaintainableArtefact(metadataflow); + metadataflow.setStructure(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=IMF:METADATA(1.0.0)")); + IdentifiableObjectSelectionImpl objectSelection = new IdentifiableObjectSelectionImpl(); + MaintainableArtefactReference maintainableArtefactReference = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)"); + + MaintainableArtefactReference maintainableArtefactReference2 = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.3)"); + objectSelection.setResolvesTo(List.of(maintainableArtefactReference, maintainableArtefactReference2)); + metadataflow.setSelections(List.of(objectSelection)); + return metadataflow; + } + + /** + * @return Dataflow object + */ + public static DataflowImpl buildDataFlow() { + DataflowImpl dataflow = new DataflowImpl(); + dataflow.setId("DF"); + dataflow.setStructure(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)")); + setMaintainableArtefact(dataflow); + return dataflow; + } + + /** + * @return AgencyScheme + */ + + public static AgencySchemeImpl buildAgencyScheme() { + AgencySchemeImpl agencyScheme = new AgencySchemeImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(agencyScheme); + agencyScheme.setId("AGENCIES"); + agencyScheme.setOrganizationId("SDMX"); + agencyScheme.setVersion(Version.createFromString("1.0")); + AgencyImpl agency1 = createAgency("AG-1"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot"); + agency1.setAnnotations(List.of(annotation)); + AgencyImpl agency2 = createAgency("AG-2"); + + + agencyScheme.setItems(List.of(agency1, agency2)); + return agencyScheme; + } + + private static AgencyImpl createAgency(String id) { + AgencyImpl agency1 = new AgencyImpl(); + agency1.setId(id); + agency1.setName(new InternationalString("Agency")); + agency1.setDescription(new InternationalString("Agency")); + + List contacts = getContacts(); + + agency1.setContacts(contacts); + return agency1; + } + + private static List getContacts() { + ContactImpl contact1 = new ContactImpl(); + contact1.setName("AG_1"); + contact1.setTelephone("9458673082"); + contact1.setFax("somedatafax"); + contact1.setEmail("test@email.com"); + contact1.setOrganizationUnit("IT"); + Map resp = new HashMap<>(); + resp.put("en", "writing"); + resp.put("fr", "ecrire"); + contact1.setResponsibility(new InternationalString(resp)); + contact1.setX400("X400"); + + ContactImpl contact2 = new ContactImpl(); + contact2.setName("AG_2"); + contact2.setTelephone("9458673082"); + contact2.setFax("somedatafax2"); + contact2.setEmail("test@email.com"); + contact2.setOrganizationUnit("IT"); + contact2.setResponsibility(new InternationalString(resp)); + contact2.setX400("X400"); + return List.of(contact1, contact2); + } + + /** + * @return CategorySchemeMap + */ + + public static CategorySchemeMapImpl buildCategorySchemeMap() { + CategorySchemeMapImpl categorySchemeMap = new CategorySchemeMapImpl(); + setMaintainableArtefact(categorySchemeMap); + categorySchemeMap.setSource(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:CatScheme(1.0)")); + categorySchemeMap.setTarget(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:CatScheme(1.1)")); + ItemMap itemMap = createItemMap("IM-1", "S-1"); + ItemMap itemMap2 = createItemMap("IM-2", "S-2"); + categorySchemeMap.setItemMaps(List.of(itemMap, itemMap2)); + return categorySchemeMap; + } + + private static ItemMap createItemMap(String target, String source) { + ItemMapImpl itemMap = new ItemMapImpl(); + itemMap.setTarget(target); + itemMap.setSource(source); + itemMap.setValidTo(Instant.parse("2022-07-17T00:00:00Z")); + itemMap.setValidFrom(Instant.parse("2022-07-17T00:00:00Z")); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Ann"); + itemMap.setAnnotations(List.of(annotation)); + return itemMap; + } + + /** + * @return ConceptSchemeMap + */ + + public static ConceptSchemeMapImpl buildConceptSchemeMap() { + ConceptSchemeMapImpl conceptSchemeMap = new ConceptSchemeMapImpl(); + setMaintainableArtefact(conceptSchemeMap); + conceptSchemeMap.setSource(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ConScheme(1.0)")); + conceptSchemeMap.setTarget(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ConScheme(1.1)")); + ItemMap itemMap = createItemMap("IM-1", "S-1"); + ItemMap itemMap2 = createItemMap("IM-2", "S-2"); + conceptSchemeMap.setItemMaps(List.of(itemMap, itemMap2)); + return conceptSchemeMap; + } + + /** + * @return DataConsumerSchemeImpl + */ + public static DataConsumerSchemeImpl buildDataConsumerScheme() { + DataConsumerSchemeImpl dataConsumerScheme = new DataConsumerSchemeImpl(); + setMaintainableArtefact(dataConsumerScheme); + dataConsumerScheme.setVersion(Version.createFromString("1.0")); + dataConsumerScheme.setId("DATA_CONSUMERS"); + DataConsumerImpl dataConsumer = new DataConsumerImpl(); + dataConsumer.setId("DC"); + dataConsumer.setName(new InternationalString("Data Consumer")); + dataConsumer.setDescription(new InternationalString("Data Consumer description")); + dataConsumer.setContacts(getContacts()); + dataConsumerScheme.setItems(List.of(dataConsumer)); + return dataConsumerScheme; + } + + /** + * @return RepresentationMap object + */ + public static RepresentationMapImpl buildRepresentationMap() { + RepresentationMapImpl representationMap = new RepresentationMapImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(representationMap); + fillSource(representationMap, "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_SOURCE(1.0)"); + fillTarget(representationMap, "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_TARGET(1.0)"); + fillRepresentationMappings(representationMap, "2022-07-17T00:00:00.000Z"); + return representationMap; + } + + public static void fillTarget(RepresentationMapImpl representationMap, String referenceUrn) { + ListReferenceValueRepresentationImpl valueRepresentation = new ListReferenceValueRepresentationImpl(); + valueRepresentation.setReference(new MaintainableArtefactReference(referenceUrn)); + representationMap.setTarget(List.of(valueRepresentation)); + } + + public static void fillSource(RepresentationMapImpl representationMap, String referenceUrn) { + ListReferenceValueRepresentationImpl valueRepresentation = new ListReferenceValueRepresentationImpl(); + valueRepresentation.setReference(new MaintainableArtefactReference(referenceUrn)); + FacetValueTypeRepresentationImpl valueRepresentation2 = new FacetValueTypeRepresentationImpl(); + valueRepresentation2.setType(FacetValueType.DATE_TIME); + representationMap.setSource(List.of(valueRepresentation, valueRepresentation2)); + } + + public static void fillRepresentationMappings(RepresentationMapImpl representationMap, String date) { + RepresentationMappingImpl representationMapping = new RepresentationMappingImpl(); + Instant instant = Instant.parse(date); + representationMapping.setValidFrom(instant); + representationMapping.setValidTo(instant); + fillSourceValues(representationMapping); + fillTargetValues(representationMapping); + representationMap.setRepresentationMappings(List.of(representationMapping)); + } + + static void fillTargetValues(RepresentationMappingImpl representationMapping) { + TargetValueImpl targetValue1 = new TargetValueImpl(); + targetValue1.setValue("targetValue1"); + TargetValueImpl targetValue2 = new TargetValueImpl(); + targetValue2.setValue("targetValue2"); + representationMapping.setTargetValues(List.of(targetValue1, targetValue2)); + } + + static void fillSourceValues(RepresentationMappingImpl representationMapping) { + MappedValueImpl mappedValue = new MappedValueImpl(); + mappedValue.setValue("mappedValue"); + mappedValue.setRegEx(true); + mappedValue.setStartIndex(0); + mappedValue.setEndIndex(10); + representationMapping.setSourceValues(List.of(mappedValue)); + } + + /** + * @return StructureMap object + */ + public static StructureMapImpl buildStructureMap() { + StructureMapImpl structureMap = new StructureMapImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(structureMap); + structureMap.setSource(new MaintainableArtefactReference("DataFSource", "EPM", "3.0", StructureClassImpl.DATAFLOW)); + structureMap.setTarget(new MaintainableArtefactReference("DataFTarget", "EPM", "3.0", StructureClassImpl.DATAFLOW)); + fillEpochMap(structureMap); + fillFixedValueMap(structureMap); + fillComponentMap(structureMap); + fillDatePattern(structureMap); + return structureMap; + } + + static void fillDatePattern(StructureMapImpl structureMap) { + DatePatternMapImpl datePatternMap = new DatePatternMapImpl(); + datePatternMap.setLocale("EN"); + datePatternMap.setSourcePattern("SOURCE"); + datePatternMap.setId("DP1"); + datePatternMap.setResolvePeriod(ResolvePeriod.MID_PERIOD); + FrequencyFormatMappingImpl frequencyFormatMapping1 = getFrequencyFormatMapping("CODE_1", "2022-11", "FR1"); + FrequencyFormatMappingImpl frequencyFormatMapping2 = getFrequencyFormatMapping("CODE_2", "2022-11", "FR2"); + datePatternMap.setMappedFrequencies(List.of(frequencyFormatMapping1, frequencyFormatMapping2)); + datePatternMap.setFrequencyDimension("Frequency_dim"); + structureMap.setDatePatternMaps(List.of(datePatternMap)); + } + + private static FrequencyFormatMappingImpl getFrequencyFormatMapping(String freqCode, String datePattern, String id) { + FrequencyFormatMappingImpl frequencyFormatMapping = new FrequencyFormatMappingImpl(); + frequencyFormatMapping.setFrequencyCode(freqCode); + frequencyFormatMapping.setDatePattern(datePattern); + frequencyFormatMapping.setId(id); + return frequencyFormatMapping; + } + + static void fillComponentMap(StructureMapImpl structureMap) { + + ComponentMapImpl componentMapDP = new ComponentMapImpl(); + componentMapDP.setSource(List.of("CompMapEpochS")); + componentMapDP.setTarget(List.of("CompMapEpochT")); + IdentifiableArtefactReferenceImpl reference = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.EPOCH_MAP, + "EPOCH1" + ); + componentMapDP.setRepresentationMap(reference); + + + ComponentMapImpl componentMapEpoch = new ComponentMapImpl(); + componentMapEpoch.setSource(List.of("CompMapDPS")); + componentMapEpoch.setTarget(List.of("CompMapDPT")); + IdentifiableArtefactReferenceImpl reference2 = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.DATE_PATTERN_MAP, + "DP1" + ); + componentMapEpoch.setRepresentationMap(reference2); + + ComponentMapImpl componentMaRep = new ComponentMapImpl(); + componentMaRep.setSource(List.of("CompMapRepS")); + componentMaRep.setTarget(List.of("CompMapRepT")); + MaintainableArtefactReference reference3 = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)"); + componentMaRep.setRepresentationMap(reference3); + + structureMap.setComponentMaps(List.of(componentMapEpoch, componentMapDP, componentMaRep)); + } + + static void fillFixedValueMap(StructureMapImpl structureMap) { + FixedValueMapImpl fixedValueMap = new FixedValueMapImpl(); + fixedValueMap.setRole(MappingRoleType.TARGET); + fixedValueMap.setComponent("STRUC_ID"); + fixedValueMap.setValue("value"); + structureMap.setFixedComponentMaps(List.of(fixedValueMap)); + } + + static void fillEpochMap(StructureMapImpl structureMap) { + EpochMapImpl epochMap = new EpochMapImpl(); + epochMap.setEpochPeriod(EpochPeriodType.MICROSECOND); + Instant instant = Instant.parse("2022-07-17T10:11:16Z"); + epochMap.setBasePeriod(instant); + epochMap.setId("EPOCH1"); + epochMap.setResolvePeriod(ResolvePeriod.MID_PERIOD); + FrequencyFormatMappingImpl frequencyFormatMapping3 = getFrequencyFormatMapping("CODE_3", "2022-11", "FR3"); + epochMap.setMappedFrequencies(List.of(frequencyFormatMapping3)); + epochMap.setFrequencyDimension("Frequency_dim"); + structureMap.setEpochMaps(List.of(epochMap)); + } + + /** + * @return Header + */ + public static Header buildHeader() throws URISyntaxException { + Header header = new Header(); + header.setId("IDREF8124"); + URI uri = new URI("https://raw.githubusercontent.com/sdmx-twg/sdmx-json/master/metadata-message/tools/schemas/2.0.0/sdmx-json-metadata-schema.json"); + header.setSchema(uri); + Instant instant = Instant.parse("2021-11-02T09:47:41Z"); + header.setPrepared(instant); + Party sender = new Party(); + sender.setId("unknown"); + header.setSender(sender); + Locale locale = new Locale("en"); + header.setContentLanguages(List.of(locale)); + return header; + } + + public static VersionableReader getVersionableReader() { + final NameableReader nameableReader = getNameableReader(); + return new VersionableReader(nameableReader); + } + + public static NameableReader getNameableReader() { + final IdentifiableReader identifiableReader = getIdentifiableReader(); + return new NameableReader(identifiableReader); + } + + public static CodelistExtensionReader getCodelistExtensionReader() { + return new CodelistExtensionReader(); + } + + public static AnnotableReader getAnnotableReader() { + return new AnnotableReader(); + } + + public static IdentifiableReader getIdentifiableReader() { + final var annotableReader = new AnnotableReader(); + return new IdentifiableReader(annotableReader); + } + + public static StructureReader getStructureReader() { + DataReader dataReader = createStructureDataReader(); + var headerReader = new MetaReader(); + return new JsonStructureReader(dataReader, headerReader); + } + + public static VersionableWriter getVersionableWriter() { + final NameableWriter nameableWriter = getNameableWriter(); + return new VersionableWriter(nameableWriter); + } + + public static NameableWriter getNameableWriter() { + final IdentifiableWriter identifiableWriter = getIdentifiableWriter(); + return new NameableWriter(identifiableWriter); + } + + public static IdentifiableWriter getIdentifiableWriter() { + final AnnotableWriter annotableWriter = getAnnotableWriter(); + return new IdentifiableWriter(annotableWriter); + } + + public static MemberSelectionReader getMemberSelectionReader() { + return new MemberSelectionReader(); + } + + public static AnnotableWriter getAnnotableWriter() { + return new AnnotableWriter(getLinksWriter()); + } + + public static CodelistExtensionWriter getCodelistExtensionWriter() { + return new CodelistExtensionWriter(getUrnAdapter()); + } + + public static ReferenceAdapter getUrnAdapter() { + return new DefaultReferenceAdapter(); + } + + public static TimeDimensionLocalRepresentationAdapter getDsdAdapter() { + return new StubDataStructureLocalRepresentationAdapter(); + } + + public static RepresentationWriter getRepresentationWriter() { + return new RepresentationWriter(getUrnAdapter()); + } + + public static ComponentWriter getComponentWriter() { + return new ComponentWriter(getIdentifiableWriter(), getRepresentationWriter(), getUrnAdapter()); + } + + public static ConceptRoleWriter getConceptRoleWriter() { + return new ConceptRoleWriter(getUrnAdapter()); + } + + public static AttributeListWriter getAttributeListWriter() { + return new AttributeListWriter(getAnnotableWriter(), getConceptRoleWriter(), getComponentWriter()); + } + + public static DimensionListWriter getDimensionListWriter() { + return new DimensionListWriter(getAnnotableWriter(), getConceptRoleWriter(), getComponentWriter()); + } + + public static MeasureListWriter getMeasureListWriter() { + return new MeasureListWriter(getAnnotableWriter(), getConceptRoleWriter(), getComponentWriter()); + } + + public static LinksWriter getLinksWriter() { + return new LinksWriter(getUrnAdapter()); + } + + public static MemberSelectionWriter getMemberSelectionWriter() { + return new MemberSelectionWriter(getDateTimeWriter()); + } + + public static DateTimeWriter getDateTimeWriter() { + return new DateTimeWriter(); + } + + public static DataKeySetsWriter getDataKeySetsWriter() { + return new DataKeySetsWriter(getAnnotableWriter(), getMemberSelectionWriter(), getDateTimeWriter()); + } + + public static ContactsWriter getContactsWriter() { + return new ContactsWriter(); + } + + public static OrganisationWriter getOrganisationWriter() { + return new OrganisationWriter(getContactsWriter(), getNameableWriter()); + } + + public static CubeRegionWriter getCubeRegionWriter() { + return new CubeRegionWriter(getMemberSelectionWriter(), getDateTimeWriter(), getAnnotableWriter()); + } + + public static DataConstraintWriter getDataConstraintWriter() { + return new DataConstraintWriter(getVersionableWriter(), getLinksWriter(), getCubeRegionWriter(), getDataKeySetsWriter(), getUrnAdapter()); + } + + + private static DataReader createStructureDataReader() { + final var annotableReader = new AnnotableReader(); + final var identifiableReader = new IdentifiableReader(annotableReader); + final var nameableReader = new NameableReader(identifiableReader); + final var versionableReader = new VersionableReader(nameableReader); + + final var categorisationReader = new CategorisationReader(versionableReader); + final var categorySchemeReader = new CategorySchemeReader(versionableReader, nameableReader); + final var conceptSchemeReader = new ConceptSchemeReader(versionableReader, nameableReader); + final var codelistExtensionReader = new CodelistExtensionReader(); + final var codeImplReader = new CodeImplReader(); + final var codeListReader = new CodelistReader(versionableReader, nameableReader, codelistExtensionReader, codeImplReader); + final var dataFlowReader = new DataFlowReader(versionableReader); + final var dataStructureDefinitionReader = new DataStructureDefinitionReader(versionableReader, identifiableReader); + final var hierarchyReader = new HierarchyReader(versionableReader, identifiableReader, nameableReader); + final var metadataFlowReader = new MetadataFlowReader(versionableReader); + final var metaDataStructureDefinitionReader = new MetaDataStructureDefinitionReader(versionableReader, identifiableReader); + final var representationMapReader = new RepresentationMapReader(versionableReader); + final var structureMapReader = new StructureMapReader(versionableReader, identifiableReader, annotableReader); + final var releaseCalendarReader = getReleaseCalendarReader(); + final var dataKeySetReader = getDataKeySetReader(); + final var cubeRegionReader = getCubeRegionReader(); + final var dataConstraintReader = new DataConstraintReader(versionableReader, releaseCalendarReader, dataKeySetReader, cubeRegionReader); + + return new DataReader( + List.of( + categorisationReader, + categorySchemeReader, + conceptSchemeReader, + codeListReader, + dataFlowReader, + dataStructureDefinitionReader, + hierarchyReader, + metadataFlowReader, + metaDataStructureDefinitionReader, + representationMapReader, + structureMapReader, + dataConstraintReader + ) + ); + } + + public static JsonStructureWriter createStructureWriter( + ByteArrayOutputStream outputStream, + ObjectMapper mapper, + DefaultHeaderProvider defaultHeaderProvider) { + var urnAdapter = new DefaultReferenceAdapter(); + var linksWriter = new LinksWriter(urnAdapter); + var representationWriter = new RepresentationWriter(urnAdapter); + var headerWriter = new MetaWriter(List.of(), defaultHeaderProvider); + final var annotableWriter = new AnnotableWriter(linksWriter); + final var identifiableWriter = new IdentifiableWriter(annotableWriter); + final var nameableWriter = new NameableWriter(identifiableWriter); + final var versionableWriter = new VersionableWriter(nameableWriter); + var componentWriter = new ComponentWriter(identifiableWriter, representationWriter, urnAdapter); + var conceptRoleWriter = new ConceptRoleWriter(urnAdapter); + var attributeListWriter = new AttributeListWriter(annotableWriter, conceptRoleWriter, componentWriter); + var dimensionListWriter = new DimensionListWriter(annotableWriter, conceptRoleWriter, componentWriter); + var groupDimensionListWriter = new GroupDimensionListWriter(identifiableWriter); + var measureListWriter = new MeasureListWriter(annotableWriter, conceptRoleWriter, componentWriter); + final var categorisationWriter = new CategorisationWriter(versionableWriter, linksWriter, urnAdapter); + final var categorySchemeWriter = new CategorySchemeWriter(versionableWriter, linksWriter, nameableWriter); + final var conceptSchemeWriter = new ConceptSchemeWriter(versionableWriter, linksWriter, nameableWriter, representationWriter); + final var codeImplWriter = new CodeWriterImpl(); + final var extensionWriter = new CodelistExtensionWriter(urnAdapter); + final var codeListWriter = new CodelistWriter(versionableWriter, linksWriter, codeImplWriter, extensionWriter, nameableWriter); + final var dataFlowWriter = new DataflowWriter(versionableWriter, linksWriter, urnAdapter); + final var dataStructureDefinitionWriter = new DataStructureDefinitionWriter( + versionableWriter, linksWriter, attributeListWriter, dimensionListWriter, groupDimensionListWriter, measureListWriter, urnAdapter, + new StubDataStructureLocalRepresentationAdapter() + ); + final var hierarchyWriter = new HierarchyWriter(versionableWriter, linksWriter, identifiableWriter, nameableWriter, urnAdapter); + final var metadataFlowWriter = new MetadataflowWriter(versionableWriter, linksWriter, urnAdapter); + final var metadataStructureDefinitionWriter = new MetadataStructureDefinitionWriter(versionableWriter, linksWriter, componentWriter, + identifiableWriter + ); + final var representationMapWriter = new RepresentationMapWriter(versionableWriter, linksWriter, annotableWriter, urnAdapter); + final var structureMapWriter = new StructureMapWriter(versionableWriter, linksWriter, annotableWriter, identifiableWriter, urnAdapter); + + final var dateTimeWriter = new DateTimeWriter(); + final var memberSelectionWriter = new MemberSelectionWriter(dateTimeWriter); + final var cubeRegionWriter = new CubeRegionWriter(memberSelectionWriter, dateTimeWriter, annotableWriter); + final var dataKeySetsWriter = new DataKeySetsWriter(annotableWriter, memberSelectionWriter, dateTimeWriter); + final var dataConstraintWriter = new DataConstraintWriter(versionableWriter, linksWriter, cubeRegionWriter, dataKeySetsWriter, urnAdapter); + + return new JsonStructureWriter( + mapper, + outputStream, + headerWriter, + List.of(categorisationWriter, categorySchemeWriter, codeListWriter, conceptSchemeWriter, + dataStructureDefinitionWriter, hierarchyWriter, metadataFlowWriter, metadataStructureDefinitionWriter, representationMapWriter, dataFlowWriter, + structureMapWriter, dataConstraintWriter + ) + ); + } + + public static void assertMaintainableArtefactsInJson(String json) { + assertThatJson(json).isPresent(); + assertThatJson(json).node("id") + .isString() + .isEqualTo("ARTEFACT"); + assertThatJson(json).node("version") + .isString() + .isEqualTo("1.2"); + assertThatJson(json).node("agencyID") + .isString() + .isEqualTo("IMF"); + assertThatJson(json).node("name") + .isString() + .isEqualTo("Maintanable artefact"); + assertThatJson(json).node("names") + .isPresent() + .isObject() + .containsEntry("en", "Maintanable artefact"); + assertThatJson(json).node("names") + .isPresent() + .isObject() + .containsEntry("fr-CA", "artefact"); + assertThatJson(json).node("description") + .isString() + .isEqualTo("Some artefact"); + assertThatJson(json).node("descriptions") + .isPresent() + .isObject() + .containsEntry("en", "Some artefact"); + assertThatJson(json).node("annotations") + .isArray() + .element(0) + .node("type") + .isEqualTo("type1"); + assertThatJson(json).node("annotations") + .isArray() + .element(0) + .node("id") + .isString() + .isEqualTo("1"); + } + + + public static DataProviderSchemeImpl buildDataProviderScheme() { + + DataProviderSchemeImpl dataProviderScheme = new DataProviderSchemeImpl(); + setMaintainableArtefact(dataProviderScheme); + dataProviderScheme.setVersion(Version.createFromString("1.0")); + dataProviderScheme.setId("DATA_PROVIDERS"); + dataProviderScheme.setPartial(true); + + DataProviderImpl dataProvider = new DataProviderImpl(); + dataProvider.setContacts(getContacts()); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Ann"); + annotation.setValue("Val"); + dataProvider.setAnnotations(List.of(annotation)); + dataProvider.setId("Prov"); + dataProvider.setName(new InternationalString("D_P")); + + dataProviderScheme.setItems(List.of(dataProvider)); + return dataProviderScheme; + } + + public static MetadataProviderScheme buildMetadataProviderScheme() { + + MetadataProviderSchemeImpl metadataProviderScheme = new MetadataProviderSchemeImpl(); + setMaintainableArtefact(metadataProviderScheme); + metadataProviderScheme.setVersion(Version.createFromString("1.0")); + metadataProviderScheme.setId("METADATA_PROVIDERS"); + metadataProviderScheme.setPartial(true); + + MetadataProviderImpl metadataProvider = new MetadataProviderImpl(); + metadataProvider.setContacts(getContacts()); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Ann"); + annotation.setValue("Val"); + metadataProvider.setAnnotations(List.of(annotation)); + metadataProvider.setId("Prov"); + metadataProvider.setName(new InternationalString("MD_P")); + + metadataProviderScheme.setItems(List.of(metadataProvider)); + return metadataProviderScheme; + } + + public static HierarchyAssociation buildHierarchyAssociation() { + HierarchyAssociationImpl hierarchyAssociation = new HierarchyAssociationImpl(); + setMaintainableArtefact(hierarchyAssociation); + hierarchyAssociation.setLinkedHierarchy(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.codelist.Hierarchy=IMF:ARTEFACT(1.2)")); + hierarchyAssociation.setContextObject(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)")); + hierarchyAssociation.setLinkedObject(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.3)")); + return hierarchyAssociation; + } + + public static MetadataConstraintImpl buildMetadataConstraint(boolean isJson) { + MetadataConstraintImpl metadataConstraint = new MetadataConstraintImpl(); + setMaintainableArtefact(metadataConstraint); + metadataConstraint.setConstraintRoleType(ConstraintRoleType.ALLOWABLE_CONTENT); + metadataConstraint.setMetadataTargetRegions(createMetadataTargetRegions(isJson)); + metadataConstraint.setReleaseCalendar(createReleaseCalendar()); + metadataConstraint.setConstrainedArtefacts(createMetadataConstrainedArtefacts()); + return metadataConstraint; + } + + private static List createMetadataConstrainedArtefacts() { + IdentifiableArtefactReferenceImpl maintainableArtefactReference = new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.base.MetadataProvider=IMF:METADATA_PROVIDERS(1.0).PR"); + return List.of(maintainableArtefactReference); + } + + private static List createMetadataTargetRegions(boolean isJson) { + MetadataTargetRegionImpl metadataTargetRegion = new MetadataTargetRegionImpl(); + metadataTargetRegion.setIncluded(true); + metadataTargetRegion.setValidTo(Instant.parse("2022-07-17T10:11:16Z")); + metadataTargetRegion.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + List memberSelectionList = getMemberSelections(false, isJson); + metadataTargetRegion.setMemberSelections(memberSelectionList); + + return List.of(metadataTargetRegion); + } + + private static List getMemberSelections(boolean isSimple, boolean isJson) { + MemberSelectionImpl memberSelection = new MemberSelectionImpl(); + memberSelection.setIncluded(false); + memberSelection.setRemovePrefix(true); + memberSelection.setComponentId("MS"); + + MemberValueImpl memberValue; + if (isSimple) { + memberValue = getMemberValueSimple(); + } else { + memberValue = getMemberValue(); + } + + memberSelection.setSelectionValues(List.of(memberValue)); + + MemberSelectionImpl memberSelection2 = new MemberSelectionImpl(); + memberSelection2.setIncluded(false); + memberSelection2.setRemovePrefix(true); + memberSelection2.setComponentId("MS2"); + BeforePeriodImpl beforePeriod = new BeforePeriodImpl(); + beforePeriod.setInclusive(true); + beforePeriod.setPeriod("2023"); + if (!isJson) { + beforePeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + beforePeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + } + + AfterPeriodImpl afterPeriod = new AfterPeriodImpl(); + afterPeriod.setInclusive(false); + afterPeriod.setPeriod("2028"); + afterPeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + afterPeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + + RangePeriodImpl rangePeriod = new RangePeriodImpl(); + TimeRangePeriodImpl timeRangePeriod = new TimeRangePeriodImpl(); + timeRangePeriod.setInclusive(true); + timeRangePeriod.setPeriod("2022"); + timeRangePeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + timeRangePeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + + rangePeriod.setStartPeriod(timeRangePeriod); + timeRangePeriod.setInclusive(false); + rangePeriod.setEndPeriod(timeRangePeriod); + rangePeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + rangePeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + + memberSelection2.setSelectionValues(List.of(beforePeriod)); + return List.of(memberSelection, memberSelection2); + } + + private static MemberValueImpl getMemberValue() { + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setValue("MEM"); + memberValue.setCascadeValue(CascadeValue.EXCLUDE_ROOT); + memberValue.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + memberValue.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + return memberValue; + } + + private static MemberValueImpl getMemberValueSimple() { + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setValue("MEM"); + return memberValue; + } + + private static ReleaseCalendar createReleaseCalendar() { + ReleaseCalendarImpl releaseCalendar = new ReleaseCalendarImpl(); + releaseCalendar.setOffset("Offset"); + releaseCalendar.setTolerance("Tolerance"); + releaseCalendar.setPeriodicity("Periodicity"); + return releaseCalendar; + } + + private static DataKeySet createDataKeySets() { + DataKeySetImpl dataKeySet = new DataKeySetImpl(); + dataKeySet.setIncluded(true); + DataKeyImpl dataKey = new DataKeyImpl(); + dataKey.setIncluded(true); + ComponentValueImpl componentValue = new ComponentValueImpl(); + componentValue.setIncluded(true); + componentValue.setComponentId("C1"); + componentValue.setRemovePrefix(true); + componentValue.setValue("Value"); + dataKey.setKeyValues(List.of(componentValue)); + dataKey.setMemberSelections(getMemberSelections(true, true)); + dataKey.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + dataKey.setValidTo(Instant.parse("2022-07-17T10:11:16Z")); + dataKeySet.setKeys(List.of(dataKey)); + + return dataKeySet; + } + + private static CubeRegion createCubeRegion() { + LocalisedMemberValueImpl selectionValue1 = new LocalisedMemberValueImpl(); + selectionValue1.setValue("selectionValue1"); + selectionValue1.setLocale("en"); + + MemberSelectionImpl memberSelection1 = new MemberSelectionImpl(); + memberSelection1.setSelectionValues(List.of(selectionValue1)); + memberSelection1.setComponentId("some component id 1"); + memberSelection1.setIncluded(true); + memberSelection1.setRemovePrefix(true); + + MemberValueImpl selectionValue2 = new MemberValueImpl(); + selectionValue2.setValue("selectionValue2"); + selectionValue2.setCascadeValue(CascadeValue.TRUE); + selectionValue2.setValidTo(Instant.parse("2020-05-12T12:00:00.000000Z")); + selectionValue2.setValidFrom(Instant.parse("2020-04-12T12:00:00.000000Z")); + MemberValueImpl selectionValue5 = new MemberValueImpl(); + selectionValue5.setValue("selectionValue5"); + + MemberSelectionImpl memberSelection2 = new MemberSelectionImpl(); + memberSelection2.setSelectionValues(List.of(selectionValue2, selectionValue5)); + memberSelection2.setComponentId("some component id 2"); + memberSelection2.setIncluded(true); + memberSelection2.setRemovePrefix(true); + + BeforePeriodImpl selectionValue3 = new BeforePeriodImpl(); + selectionValue3.setPeriod("2020"); + AfterPeriodImpl selectionValue4 = new AfterPeriodImpl(); + selectionValue4.setPeriod("2021"); + + CubeRegionKeyImpl cubeRegionKey1 = new CubeRegionKeyImpl(); + cubeRegionKey1.setComponentId("123"); + cubeRegionKey1.setIncluded(true); + cubeRegionKey1.setRemovePrefix(true); + cubeRegionKey1.setValidFrom(Instant.parse("2020-04-12T12:00:00.000000Z")); + cubeRegionKey1.setValidTo(Instant.parse("2022-04-12T12:00:00.000000Z")); + cubeRegionKey1.setSelectionValues(List.of(selectionValue3, selectionValue4)); + + CubeRegionImpl cubeRegion = new CubeRegionImpl(); + cubeRegion.setIncluded(true); + cubeRegion.setMemberSelections(List.of(memberSelection1, memberSelection2)); + cubeRegion.setCubeRegionKeys(List.of(cubeRegionKey1)); + cubeRegion.setAnnotations(getAnnotations()); + + return cubeRegion; + } + + public static MetadataProvisionAgreement buildMetadataProvisionAgreement() { + MetadataProvisionAgreementImpl metadataProvisionAgreement = new MetadataProvisionAgreementImpl(); + setMaintainableArtefact(metadataProvisionAgreement); + metadataProvisionAgreement.setControlledStructureUsage(new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=IMF:ARTEFACT(1.2)")); + metadataProvisionAgreement.setMetadataProvider(new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.base.MetadataProvider=IMF:METADATA_PROVIDERS(1.0).PR")); + return metadataProvisionAgreement; + } + + public static OrganisationSchemeMap buildOrganisationSchemeMap() { + OrganisationSchemeMapImpl organisationSchemeMap = new OrganisationSchemeMapImpl(); + setMaintainableArtefact(organisationSchemeMap); + organisationSchemeMap.setSource(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.base.AgencyScheme=SDMX:AGENCIES(1.0)")); + organisationSchemeMap.setTarget(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.base.AgencyScheme=SDMX:AGENCIES(1.0)")); + ItemMap itemMap = createItemMap("IM-1", "S-1"); + ItemMap itemMap2 = createItemMap("IM-2", "S-2"); + organisationSchemeMap.setItemMaps(List.of(itemMap, itemMap2)); + return organisationSchemeMap; + } + + public static Process buildProcess() { + ProcessImpl process = new ProcessImpl(); + setMaintainableArtefact(process); + List processSteps = new ArrayList<>(); + ProcessStepImpl processStep = new ProcessStepImpl(); + processStep.setId("ProcStep"); + processStep.setName(new InternationalString("ProcessStep")); + processStep.setDescription(new InternationalString("ProcessStep description")); + + ProcessArtefactImpl processArtefact = new ProcessArtefactImpl(); + processArtefact.setLocalId("Loc"); + processArtefact.setArtefact(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.process.ProcessStep=IMF:Artefact(1.0)")); + processArtefact.setAnnotations(getAnnotations()); + processStep.setInputs(List.of(processArtefact)); + processStep.setOutputs(List.of(processArtefact)); + + TransitionImpl transition = new TransitionImpl(); + transition.setId("Trans"); + transition.setLocalId("Loc"); + transition.setTargetProcessStep("ST"); + transition.setCondition(new InternationalString("Doo")); + processStep.setTransitions(List.of(transition)); + + ComputationImpl computation = new ComputationImpl(); + computation.setLocalId("LocId"); + computation.setSoftwareLanguage("SoftwareLanguage"); + computation.setSoftwarePackage("SoftwarePackage"); + computation.setSoftwareVersion("SoftwareVersion"); + computation.setAnnotations(getAnnotations()); + computation.setDescription(new InternationalString("Computation Description")); + processStep.setComputation(computation); + + ProcessStepImpl processStepChild = new ProcessStepImpl(); + processStepChild.setId("ProcessChild"); + processStepChild.setAnnotations(getAnnotations()); + processStepChild.setName(new InternationalString("ProcessStepChild")); + processStep.setChildren(List.of(processStepChild)); + processStep.setAnnotations(getAnnotations()); + processSteps.add(processStep); + process.setSteps(processSteps); + + return process; + } + + + public static ProvisionAgreement buildProvisionAgreement() { + ProvisionAgreementImpl provisionAgreement = new ProvisionAgreementImpl(); + setMaintainableArtefact(provisionAgreement); + provisionAgreement.setControlledStructureUsage( + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=IMF:ARTEFACT(1.2)")); + provisionAgreement.setDataProvider( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP")); + return provisionAgreement; + } + + public static ReportingTaxonomy buildReportingTaxonomy() { + ReportingTaxonomyImpl reportingTaxonomy = new ReportingTaxonomyImpl(); + setMaintainableArtefact(reportingTaxonomy); + ReportingCategoryImpl reportingCategory1 = new ReportingCategoryImpl(); + reportingCategory1.setId("RC-1"); + reportingCategory1.setName(new InternationalString("ReportingCat")); + reportingCategory1.setDescription(new InternationalString("ReportingCat description")); + reportingCategory1.setAnnotations(getAnnotations()); + reportingCategory1.setFlows(List.of( + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataS2(3.0)"), + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataS1(3.0)") + + )); + ReportingCategoryImpl reportingCategory2 = new ReportingCategoryImpl(); + reportingCategory2.setId("RC-2"); + reportingCategory2.setName(new InternationalString("ReportingCat2")); + reportingCategory2.setDescription(new InternationalString("ReportingCat2 description")); + reportingCategory2.setAnnotations(getAnnotations()); + reportingCategory2.setStructures(List.of( + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=EPM:DataS2(3.0)"), + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=EPM:DataS1(3.0)") + )); + reportingCategory1.setHierarchy(List.of(reportingCategory2)); + reportingTaxonomy.setItems(List.of(reportingCategory1)); + return reportingTaxonomy; + } + + public static ReportingTaxonomyMap buildReportingTaxonomyMap() { + ReportingTaxonomyMapImpl reportingTaxonomyMap = new ReportingTaxonomyMapImpl(); + setMaintainableArtefact(reportingTaxonomyMap); + reportingTaxonomyMap.setSource(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.categoryscheme.ReportingTaxonomy=SDMX:REP_SOURCE(1.0)")); + reportingTaxonomyMap.setTarget(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.categoryscheme.ReportingTaxonomy=SDMX:REP_TARGET(1.0)")); + ItemMap itemMap = createItemMap("IM-1", "S-1"); + ItemMap itemMap2 = createItemMap("IM-2", "S-2"); + reportingTaxonomyMap.setItemMaps(List.of(itemMap, itemMap2)); + return reportingTaxonomyMap; + } + + public static ValueList buildValueList() { + ValueListImpl valueList = new ValueListImpl(); + setMaintainableArtefact(valueList); + ValueItemImpl valueItem = new ValueItemImpl(); + valueItem.setId("VAL-1"); + Map names = new HashMap<>(); + names.put("en", "value"); + names.put("fr", "val"); + Map descriptions = new HashMap<>(); + descriptions.put("en", "it is value"); + descriptions.put("fr", "c'est val"); + valueItem.setName(new InternationalString(names)); + valueItem.setDescription(new InternationalString(descriptions)); + valueItem.setAnnotations(getAnnotations()); + + ValueItemImpl valueItem2 = new ValueItemImpl(); + valueItem2.setId("VAL-2"); + valueItem2.setName(new InternationalString("smth")); + valueItem2.setDescription(new InternationalString("smth description")); + valueItem2.setAnnotations(getAnnotations()); + valueList.setItems(List.of(valueItem, valueItem2)); + return valueList; + } + + public static DataConstraint buildDataConstraintXml() { + DataConstraintImpl dataConstraint = new DataConstraintImpl(); + setMaintainableArtefact(dataConstraint); + dataConstraint.setConstraintRoleType(ConstraintRoleType.ALLOWABLE_CONTENT); + CubeRegionImpl cubeRegion = new CubeRegionImpl(); + cubeRegion.setIncluded(true); + cubeRegion.setAnnotations(getAnnotations()); + CubeRegionKeyImpl cubeRegionKey = new CubeRegionKeyImpl(); + cubeRegionKey.setComponentId("CubeReg"); + cubeRegionKey.setIncluded(true); + cubeRegionKey.setRemovePrefix(true); + cubeRegionKey.setValidTo(Instant.parse("2022-07-17T10:11:16Z")); + cubeRegionKey.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + cubeRegionKey.setSelectionValues(List.of(getMemberValue())); + cubeRegion.setCubeRegionKeys(List.of(cubeRegionKey)); + cubeRegion.setMemberSelections(getMemberSelections(true, false)); + dataConstraint.setCubeRegions(List.of(cubeRegion)); + dataConstraint.setReleaseCalendar(createReleaseCalendar()); + DataKeySetImpl dataKeySet = new DataKeySetImpl(); + dataKeySet.setIncluded(true); + DataKeyImpl dataKey = new DataKeyImpl(); + dataKey.setIncluded(true); + ComponentValueImpl componentValue = new ComponentValueImpl(); + componentValue.setIncluded(true); + componentValue.setComponentId("C1"); + componentValue.setRemovePrefix(true); + componentValue.setValue("Value"); + dataKey.setKeyValues(List.of(componentValue)); + dataKey.setMemberSelections(getMemberSelections(true, false)); + dataKey.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + dataKey.setValidTo(Instant.parse("2022-07-17T10:11:16Z")); + dataKeySet.setKeys(List.of(dataKey)); + dataConstraint.setDataContentKeys(List.of(dataKeySet)); + IdentifiableArtefactReferenceImpl maintainableArtefactReference = new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).PR"); + dataConstraint.setConstrainedArtefacts(List.of(maintainableArtefactReference)); + return dataConstraint; + } + + public static GeographicCodelist buildGeographicCodelist() { + GeographicCodelistImpl geographicCodelist = new GeographicCodelistImpl(); + setMaintainableArtefact(geographicCodelist); + geographicCodelist.setItems(getGeoFeatureSetCodes()); + geographicCodelist.setExtensions(getExtensions()); + geographicCodelist.setPartial(true); + return geographicCodelist; + } + + private static List getGeoFeatureSetCodes() { + GeoFeatureSetCodeImpl geoFeatureSetCode1 = new GeoFeatureSetCodeImpl(); + geoFeatureSetCode1.setValue("Value1"); + geoFeatureSetCode1.setDescription(new InternationalString("code 1 desc")); + geoFeatureSetCode1.setId("CODE1"); + geoFeatureSetCode1.setName(new InternationalString("code 1")); + geoFeatureSetCode1.setParentId("CODE2"); + GeoFeatureSetCodeImpl geoFeatureSetCode2 = new GeoFeatureSetCodeImpl(); + geoFeatureSetCode2.setValue("Value2"); + geoFeatureSetCode2.setDescription(new InternationalString("code 2 desc")); + geoFeatureSetCode2.setId("CODE2"); + geoFeatureSetCode2.setName(new InternationalString("code 2")); + return List.of(geoFeatureSetCode1, geoFeatureSetCode2); + } + + public static GeoGridCodelist buildGeoGridCodelist() { + GeoGridCodelistImpl geoGridCodelist = new GeoGridCodelistImpl(); + setMaintainableArtefact(geoGridCodelist); + geoGridCodelist.setItems(getGridCodes()); + geoGridCodelist.setExtensions(getExtensions()); + geoGridCodelist.setPartial(true); + geoGridCodelist.setGridDefinition("DEFINITION"); + return geoGridCodelist; + } + + private static List getGridCodes() { + GridCodeImpl gridCode = new GridCodeImpl(); + gridCode.setGeoCell("Value1"); + gridCode.setDescription(new InternationalString("code 1 desc")); + gridCode.setId("CODE1"); + gridCode.setName(new InternationalString("code 1")); + gridCode.setParentId("CODE2"); + GridCodeImpl gridCode2 = new GridCodeImpl(); + gridCode2.setGeoCell("Value2"); + gridCode2.setDescription(new InternationalString("code 2 desc")); + gridCode2.setId("CODE2"); + gridCode2.setName(new InternationalString("code 2")); + return List.of(gridCode, gridCode2); + } + + private static List getAnnotations() { + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot"); + return List.of(annotation); + } + + public static OrganisationUnitScheme buildOrganisationUnitScheme() { + OrganisationUnitSchemeImpl organisationUnitScheme = new OrganisationUnitSchemeImpl(); + setMaintainableArtefact(organisationUnitScheme); + organisationUnitScheme.setVersion(Version.createFromString("1.0")); + organisationUnitScheme.setPartial(true); + OrganisationUnitImpl organisationUnit = new OrganisationUnitImpl(); + organisationUnit.setAnnotations(getAnnotations()); + organisationUnit.setContacts(getContacts()); + organisationUnit.setId("OrgUnit"); + organisationUnit.setName(new InternationalString("OrganisationUnit")); + organisationUnit.setDescription(new InternationalString("OrganisationUnit description")); + OrganisationUnitImpl organisationUnit2 = new OrganisationUnitImpl(); + organisationUnit2.setId("OrgUnit2"); + organisationUnit2.setName(new InternationalString("OrganisationUnit")); + organisationUnit.setHierarchy(List.of(organisationUnit2)); + organisationUnitScheme.setItems(List.of(organisationUnit, organisationUnit2)); + return organisationUnitScheme; + } + + public static ContactReader getContactReader() { + return new ContactReader(); + } + + public static OrganisationReader getOrganisationReader() { + return new OrganisationReader(getContactReader(), getNameableReader()); + } + + public static ReleaseCalendarReader getReleaseCalendarReader() { + return new ReleaseCalendarReader(); + } + + public static DataKeySetReader getDataKeySetReader() { + return new DataKeySetReader(getAnnotableReader(), getMemberSelectionReader()); + } + + public static CubeRegionReader getCubeRegionReader() { + return new CubeRegionReader(getMemberSelectionReader(), getAnnotableReader()); + } + + public static CodeImplReader getCodeImplReader() { + return new CodeImplReader(); + } + + public static CodeWriterImpl getCodeImplWriter() { + return new CodeWriterImpl(); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/TestUtils.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/TestUtils.java new file mode 100644 index 0000000..76b6dd4 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/TestUtils.java @@ -0,0 +1,40 @@ +package com.epam.jsdmx.json20.structure; + +public class TestUtils { + + public static final String CATEGORISATION_JSON = "/serialization.expected/categorisation.json"; + public static final String CATEGORY_SCHEMA_JSON = "/serialization.expected/category-schema.json"; + public static final String CATEGORY_SCHEMA_2_JSON = "/deserialization.expected/category-schema2.json"; + public static final String CODE_LIST_JSON = "/serialization.expected/codelist.json"; + public static final String CONCEPT_SCHEMA_JSON = "/serialization.expected/concept-scheme.json"; + public static final String HIERARCHY_JSON = "/serialization.expected/hierarchy.json"; + public static final String HIERARCHY_HI_JSON = "/deserialization.expected/hierarchy.json"; + public static final String DATA_FLOW_JSON = "/serialization.expected/data-flow.json"; + public static final String METADATA_FLOW_JSON = "/serialization.expected/metadata-flow.json"; + public static final String METADATA_STRUCTURE_DEF_JSON = "/serialization.expected/metadata-structure-definition.json"; + public static final String REPRESENTATION_MAP_JSON = "/serialization.expected/representation-map.json"; + public static final String STRUCTURE_MAP_JSON = "/deserialization.expected/structure-maps-full.json"; + public static final String STRUCTURE_MAP_LIST_JSON = "/deserialization.expected/structure-maps-list-full.json"; + public static final String DATA_CONSTRAINT_JSON = "/serialization.expected/data-constraint.json"; + public static final String DATA_CONSTRAINT_EMPTY_JSON = "/serialization.expected/data-constraint-empty.json"; + public static final String DATA_STRUCTURE_DEFINITION_JSON = "/serialization.expected/data-structure-definition.json"; + + public static final String AGENCY_SCHEME_JSON = "/serialization.expected/agency-scheme.json"; + public static final String DATA_CONSUMER_SCHEME_JSON = "/serialization.expected/data-consumer-scheme.json"; + public static final String DATA_PROVIDER_SCHEME_JSON = "/serialization.expected/data-provider-scheme.json"; + public static final String HIERARCHY_ASSOCIATION_JSON = "/serialization.expected/hierarchy-association.json"; + public static final String METADATA_PROVIDER_SCHEME_JSON = "/serialization.expected/metadata-provider-scheme.json"; + public static final String ORGANISATION_UNIT_SCHEME_JSON = "/serialization.expected/organisation-unit-scheme.json"; + public static final String REPORTING_TAXONOMY_JSON = "/serialization.expected/reporting-taxonomy.json"; + public static final String VALUE_LIST_JSON = "/serialization.expected/valuelist.json"; + public static final String REPORTING_TAXONOMY_MAP_JSON = "/serialization.expected/reporting-taxonomy-map.json"; + public static final String CATEGORY_SCHEME_MAP_JSON = "/serialization.expected/category-scheme-map.json"; + public static final String CONCEPT_SCHEME_MAP_JSON = "/serialization.expected/concept-scheme-map.json"; + public static final String ORGANISATION_SCHEME_MAP_JSON = "/serialization.expected/organisation-scheme-map.json"; + public static final String PROVISION_AGREEMENT_JSON = "/serialization.expected/provision-agreement.json"; + public static final String METADATA_PROVISION_AGREEMENT_JSON = "/serialization.expected/metadata-provision-agreement.json"; + public static final String PROCESS_JSON = "/serialization.expected/process.json"; + public static final String METADATA_CONSTRAINT_JSON = "/serialization.expected/metadata-constraint.json"; + public static final String GEOCODELIST_JSON = "/serialization.expected/geocodelist.json"; + public static final String GEOGRIDCODELIST_JSON = "/serialization.expected/geogridcodelist.json"; +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/ArtefactAssertion.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/ArtefactAssertion.java new file mode 100644 index 0000000..7ff6876 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/ArtefactAssertion.java @@ -0,0 +1,91 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Categorisation; +import com.epam.jsdmx.infomodel.sdmx30.CategoryScheme; +import com.epam.jsdmx.infomodel.sdmx30.Codelist; +import com.epam.jsdmx.infomodel.sdmx30.ConceptScheme; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinition; +import com.epam.jsdmx.infomodel.sdmx30.Dataflow; +import com.epam.jsdmx.infomodel.sdmx30.Hierarchy; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinition; +import com.epam.jsdmx.infomodel.sdmx30.Metadataflow; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMap; +import com.epam.jsdmx.infomodel.sdmx30.StructureMap; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public class ArtefactAssertion { + + private Artefacts artefacts; + + public static ArtefactAssertion assertThat(Artefacts artefact) { + return new ArtefactAssertion(artefact); + } + + ArtefactAssertion hasCategorisation(Set categorisations) { + assertEquals(artefacts.getCategorisations(), categorisations); + return this; + } + + ArtefactAssertion hasCategoryScheme(Set categorySchemes) { + assertEquals(artefacts.getCategorySchemes(), categorySchemes); + return this; + } + + ArtefactAssertion hasCodeLists(Set codelists) { + assertEquals(artefacts.getCodelists(), codelists); + return this; + } + + ArtefactAssertion hasConceptSchemes(Set conceptSchemes) { + assertEquals(artefacts.getConceptSchemes(), conceptSchemes); + return this; + } + + ArtefactAssertion hasHierarchies(Set hierarchies) { + assertEquals(artefacts.getHierarchies(), hierarchies); + return this; + } + + ArtefactAssertion hasDataFlows(Set dataflows) { + assertEquals(artefacts.getDataflows(), dataflows); + return this; + } + + ArtefactAssertion hasMetadataFlows(Set metadataflows) { + assertEquals(artefacts.getMetadataflows(), metadataflows); + return this; + } + + ArtefactAssertion hasDSD(Set dataStructureDefinitions) { + assertEquals(artefacts.getDataStructures(), dataStructureDefinitions); + return this; + } + + ArtefactAssertion hasMDSD(Set metadataStructureDefinitions) { + assertEquals(artefacts.getMetadataStructureDefinitions(), metadataStructureDefinitions); + return this; + } + + ArtefactAssertion hasRepresentationMaps(Set representationMaps) { + assertEquals(artefacts.getRepresentationMaps(), representationMaps); + return this; + } + + ArtefactAssertion hasStructureMaps(Set structureMaps) { + assertEquals(artefacts.getStructureMaps(), structureMaps); + return this; + } + + ArtefactAssertion hasDataConstraint(Set dataConstraintMaps) { + assertEquals(artefacts.getDataConstraints(), dataConstraintMaps); + return this; + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/BaseJsonReaderTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/BaseJsonReaderTest.java new file mode 100644 index 0000000..a2a649e --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/BaseJsonReaderTest.java @@ -0,0 +1,128 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.io.InputStream; +import java.util.stream.Stream; + +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.json20.structure.TestUtils; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +class BaseJsonReaderTest { + + @Spy + VersionableReader versionableReader = MaintainableArtifactsTestUtils.getVersionableReader(); + + @Spy + OrganisationReader organisationReader = MaintainableArtifactsTestUtils.getOrganisationReader(); + + @Spy + NameableReader nameableReader = MaintainableArtifactsTestUtils.getNameableReader(); + + @Spy + AnnotableReader annotableReader = MaintainableArtifactsTestUtils.getAnnotableReader(); + + @Spy + private IdentifiableReader identifiableReader = MaintainableArtifactsTestUtils.getIdentifiableReader(); + + @Spy + private MemberSelectionReader memberSelectionReader = new MemberSelectionReader(); + + private static Stream testArtefactReaders() { + + VersionableReader versionableReader = Mockito.spy(MaintainableArtifactsTestUtils.getVersionableReader()); + IdentifiableReader identifiableReader = Mockito.spy(MaintainableArtifactsTestUtils.getIdentifiableReader()); + NameableReader nameableReader = Mockito.spy(MaintainableArtifactsTestUtils.getNameableReader()); + AnnotableReader annotableReader = Mockito.spy(MaintainableArtifactsTestUtils.getAnnotableReader()); + OrganisationReader organisationReader = Mockito.spy(MaintainableArtifactsTestUtils.getOrganisationReader()); + MemberSelectionReader memberSelectionReader = Mockito.spy(MaintainableArtifactsTestUtils.getMemberSelectionReader()); + ReleaseCalendarReader releaseCalendarReader = Mockito.spy(MaintainableArtifactsTestUtils.getReleaseCalendarReader()); + AgencySchemeReader agencySchemeReader = new AgencySchemeReader(versionableReader, organisationReader); + CategorySchemeMapReader categorySchemeMapReader = new CategorySchemeMapReader(versionableReader); + ConceptSchemeMapReader conceptSchemeMapReader = new ConceptSchemeMapReader(versionableReader); + DataConsumerSchemeReader dataConsumerSchemeReader = new DataConsumerSchemeReader(versionableReader, organisationReader); + DataProviderSchemeReader dataProviderSchemeReader = new DataProviderSchemeReader(versionableReader, organisationReader); + HierarchyAssociationReader hierarchyAssociationReader = new HierarchyAssociationReader(versionableReader); + MetadataConstraintReader metadataConstraintReader = new MetadataConstraintReader(versionableReader, memberSelectionReader, releaseCalendarReader); + MetadataProviderSchemeReader metadataProviderSchemeReader = new MetadataProviderSchemeReader(versionableReader, organisationReader); + MetadataProvisionAgreementReader metadataProvisionAgreementReader = new MetadataProvisionAgreementReader(versionableReader); + OrganisationSchemeMapReader organisationSchemeMapReader = new OrganisationSchemeMapReader(versionableReader); + OrganisationUnitSchemeReader organisationUnitSchemeReader = new OrganisationUnitSchemeReader(versionableReader, organisationReader); + ProcessReader processReader = new ProcessReader(versionableReader, nameableReader, annotableReader, identifiableReader); + ProvisionAgreementReader provisionAgreementReader = new ProvisionAgreementReader(versionableReader); + ReportingTaxonomyMapReader reportingTaxonomyMapReader = new ReportingTaxonomyMapReader(versionableReader); + ReportingTaxonomyReader reportingTaxonomyReader = new ReportingTaxonomyReader(versionableReader, nameableReader); + ValueListReader valueListReader = new ValueListReader(versionableReader, annotableReader); + DataKeySetReader dataKeySetReader = new DataKeySetReader(annotableReader, memberSelectionReader); + CubeRegionReader cubeRegionReader = new CubeRegionReader(memberSelectionReader, annotableReader); + DataConstraintReader dataConstraintReader = new DataConstraintReader(versionableReader, releaseCalendarReader, dataKeySetReader, cubeRegionReader); + CodelistExtensionReader codelistExtensionReader = new CodelistExtensionReader(); + GeoFeatureSetCodeReader geoFeatureSetCodeReader = new GeoFeatureSetCodeReader(); + GeographicCodelistReader geographicCodelistReader = new GeographicCodelistReader( + versionableReader, + nameableReader, + codelistExtensionReader, + geoFeatureSetCodeReader + ); + GridCodeReader gridCodeReader = new GridCodeReader(); + GeoGridCodelistReader geoGridCodelistReader = new GeoGridCodelistReader(versionableReader, codelistExtensionReader, gridCodeReader, nameableReader); + return Stream.of( + Arguments.of(TestUtils.ORGANISATION_UNIT_SCHEME_JSON, organisationUnitSchemeReader, MaintainableArtifactsTestUtils.buildOrganisationUnitScheme()), + Arguments.of(TestUtils.AGENCY_SCHEME_JSON, agencySchemeReader, MaintainableArtifactsTestUtils.buildAgencyScheme()), + Arguments.of(TestUtils.CATEGORY_SCHEME_MAP_JSON, categorySchemeMapReader, MaintainableArtifactsTestUtils.buildCategorySchemeMap()), + Arguments.of(TestUtils.CONCEPT_SCHEME_MAP_JSON, conceptSchemeMapReader, MaintainableArtifactsTestUtils.buildConceptSchemeMap()), + Arguments.of(TestUtils.DATA_CONSUMER_SCHEME_JSON, dataConsumerSchemeReader, MaintainableArtifactsTestUtils.buildDataConsumerScheme()), + Arguments.of(TestUtils.DATA_PROVIDER_SCHEME_JSON, dataProviderSchemeReader, MaintainableArtifactsTestUtils.buildDataProviderScheme()), + Arguments.of(TestUtils.HIERARCHY_ASSOCIATION_JSON, hierarchyAssociationReader, MaintainableArtifactsTestUtils.buildHierarchyAssociation()), + Arguments.of(TestUtils.METADATA_CONSTRAINT_JSON, metadataConstraintReader, MaintainableArtifactsTestUtils.buildMetadataConstraint(true)), + Arguments.of(TestUtils.METADATA_PROVIDER_SCHEME_JSON, metadataProviderSchemeReader, MaintainableArtifactsTestUtils.buildMetadataProviderScheme()), + Arguments.of( + TestUtils.METADATA_PROVISION_AGREEMENT_JSON, + metadataProvisionAgreementReader, + MaintainableArtifactsTestUtils.buildMetadataProvisionAgreement() + ), + Arguments.of(TestUtils.ORGANISATION_SCHEME_MAP_JSON, organisationSchemeMapReader, MaintainableArtifactsTestUtils.buildOrganisationSchemeMap()), + Arguments.of(TestUtils.PROCESS_JSON, processReader, MaintainableArtifactsTestUtils.buildProcess()), + Arguments.of(TestUtils.PROVISION_AGREEMENT_JSON, provisionAgreementReader, MaintainableArtifactsTestUtils.buildProvisionAgreement()), + Arguments.of(TestUtils.REPORTING_TAXONOMY_MAP_JSON, reportingTaxonomyMapReader, MaintainableArtifactsTestUtils.buildReportingTaxonomyMap()), + Arguments.of(TestUtils.REPORTING_TAXONOMY_JSON, reportingTaxonomyReader, MaintainableArtifactsTestUtils.buildReportingTaxonomy()), + Arguments.of(TestUtils.VALUE_LIST_JSON, valueListReader, MaintainableArtifactsTestUtils.buildValueList()), + Arguments.of(TestUtils.DATA_CONSTRAINT_JSON, dataConstraintReader, MaintainableArtifactsTestUtils.buildDataConstraint()), + Arguments.of(TestUtils.GEOCODELIST_JSON, geographicCodelistReader, MaintainableArtifactsTestUtils.buildGeographicCodelist()), + Arguments.of(TestUtils.GEOGRIDCODELIST_JSON, geoGridCodelistReader, MaintainableArtifactsTestUtils.buildGeoGridCodelist()) + ); + } + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + } + + public JsonParser createParser(String resource) throws IOException { + InputStream resourceAsStream = BaseJsonReaderTest.class.getResourceAsStream(resource); + JsonFactory factory = new JsonFactory(); + return factory.createParser(resourceAsStream); + } + + @ParameterizedTest + @MethodSource("testArtefactReaders") + void readJson(String path, + MaintainableReader reader, + T expected) throws IOException { + JsonParser parser = createParser(path); + T actual = (T) reader.readAndClose(parser); + assertTrue(expected.deepEquals(actual)); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/CategorisationReaderTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/CategorisationReaderTest.java new file mode 100644 index 0000000..9525648 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/CategorisationReaderTest.java @@ -0,0 +1,33 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.TestUtils.CATEGORISATION_JSON; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.CategorisationImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class CategorisationReaderTest extends BaseJsonReaderTest { + + @InjectMocks + private CategorisationReader categorisationReader; + + @Test + void readCategorisationFromJsonTest() throws IOException { + //given + JsonParser parser = createParser(CATEGORISATION_JSON); + CategorisationImpl expected = MaintainableArtifactsTestUtils.buildCategorisation(); + + //when + CategorisationImpl actual = (CategorisationImpl) categorisationReader.readAndClose(parser); + + //then + assertTrue(expected.deepEquals(actual)); + } + +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/CategorySchemeReaderTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/CategorySchemeReaderTest.java new file mode 100644 index 0000000..723fe42 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/CategorySchemeReaderTest.java @@ -0,0 +1,54 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.TestUtils.CATEGORY_SCHEMA_2_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.CATEGORY_SCHEMA_JSON; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.CategoryScheme; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class CategorySchemeReaderTest extends BaseJsonReaderTest { + + @InjectMocks + private CategorySchemeReader categorySchemeReader; + + @Test + void readCategorySchemeFromJsonTest() throws IOException { + //given + JsonParser parser = createParser(CATEGORY_SCHEMA_JSON); + CategoryScheme expected = MaintainableArtifactsTestUtils.buildCategoryScheme(); + + //when + CategoryScheme actual = (CategoryScheme) categorySchemeReader.readAndClose(parser); + + //then + assertTrue(expected.deepEquals(actual)); + } + + @Test + void testCategoryScheme2() throws IOException { + //given + JsonParser parser = createParser(CATEGORY_SCHEMA_2_JSON); + CategoryScheme expected = getCategorySchemeExpected(); + + //when + CategorySchemeImpl actual = (CategorySchemeImpl) categorySchemeReader.readAndClose(parser); + + //then + assertTrue(expected.deepEquals(actual)); + } + + private CategoryScheme getCategorySchemeExpected() { + CategorySchemeImpl categoryScheme = new CategorySchemeImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(categoryScheme); + categoryScheme.setPartial(true); + return categoryScheme; + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/CodelistReaderTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/CodelistReaderTest.java new file mode 100644 index 0000000..a0239e5 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/CodelistReaderTest.java @@ -0,0 +1,51 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.TestUtils.CODE_LIST_JSON; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.io.InputStream; + +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +class CodelistReaderTest { + + @InjectMocks + public CodelistReader codeListReader; + @Spy + private VersionableReader versionableWriter = MaintainableArtifactsTestUtils.getVersionableReader(); + @Spy + private NameableReader nameableWriter = MaintainableArtifactsTestUtils.getNameableReader(); + @Spy + private CodelistExtensionReader codelistExtensionReader = MaintainableArtifactsTestUtils.getCodelistExtensionReader(); + @Spy + private CodeImplReader codeImplReader = MaintainableArtifactsTestUtils.getCodeImplReader(); + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + } + + @Test + void readCodeListFromJsonTest() throws IOException { + //given + InputStream resourceAsStream = CodelistReaderTest.class.getResourceAsStream(CODE_LIST_JSON); + JsonFactory factory = new JsonFactory(); + JsonParser parser = factory.createParser(resourceAsStream); + CodelistImpl expected = MaintainableArtifactsTestUtils.buildCodeList(); + //when + CodelistImpl actual = (CodelistImpl) codeListReader.readAndClose(parser); + //then + assertTrue(expected.deepEquals(actual)); + } +} + diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/ConceptSchemeReaderTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/ConceptSchemeReaderTest.java new file mode 100644 index 0000000..702df15 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/ConceptSchemeReaderTest.java @@ -0,0 +1,54 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.TestUtils.CONCEPT_SCHEMA_JSON; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.BaseFacetImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptScheme; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.FacetType; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class ConceptSchemeReaderTest extends BaseJsonReaderTest { + + @InjectMocks + public ConceptSchemeReader conceptSchemeReader; + + @Test + void readConceptSchemeFromJsonTest() throws IOException { + //given + JsonParser parser = createParser(CONCEPT_SCHEMA_JSON); + ConceptSchemeImpl expected = MaintainableArtifactsTestUtils.buildConceptScheme(); + + //when + ConceptSchemeImpl actual = (ConceptSchemeImpl) conceptSchemeReader.readAndClose(parser); + + //then + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readConceptWithEnumeration() throws Exception { + //given + JsonParser parser = createParser("/serialization.expected/concept-scheme-enumerated-concept.json"); + + //when + ConceptScheme actual = (ConceptScheme) conceptSchemeReader.readAndClose(parser); + + //then + assertThat(actual.getItems()).hasSize(5); + final var multilingualFacet = new BaseFacetImpl(); + multilingualFacet.setType(FacetType.IS_MULTILINGUAL); + multilingualFacet.setValue("true"); + + assertThat(actual.getItems().get(3).getCoreRepresentation().nonEnumerated()) + .contains(multilingualFacet); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/DataConstraintReaderTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/DataConstraintReaderTest.java new file mode 100644 index 0000000..b8052d6 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/DataConstraintReaderTest.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.TestUtils.DATA_CONSTRAINT_JSON; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.io.InputStream; + +import com.epam.jsdmx.infomodel.sdmx30.DataConstraintImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +public class DataConstraintReaderTest { + + @InjectMocks + private DataConstraintReader dataConstraintReader; + @Spy + private VersionableReader versionableReader = MaintainableArtifactsTestUtils.getVersionableReader(); + @Spy + private ReleaseCalendarReader releaseCalendarReader = MaintainableArtifactsTestUtils.getReleaseCalendarReader(); + @Spy + private DataKeySetReader dataKeySetReader = MaintainableArtifactsTestUtils.getDataKeySetReader(); + @Spy + private CubeRegionReader cubeRegionReader = MaintainableArtifactsTestUtils.getCubeRegionReader(); + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + } + + @Test + void readDataConstraintFromJsonTest() throws IOException { + //given + InputStream resourceAsStream = DataConstraintReaderTest.class.getResourceAsStream(DATA_CONSTRAINT_JSON); + JsonFactory factory = new JsonFactory(); + JsonParser parser = factory.createParser(resourceAsStream); + DataConstraintImpl expected = MaintainableArtifactsTestUtils.buildDataConstraint(); + + //when + DataConstraintImpl actual = (DataConstraintImpl) dataConstraintReader.readAndClose(parser); + + //then + assertTrue(expected.deepEquals(actual)); + } + +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/DataReaderTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/DataReaderTest.java new file mode 100644 index 0000000..8dd0710 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/DataReaderTest.java @@ -0,0 +1,138 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.Categorisation; +import com.epam.jsdmx.infomodel.sdmx30.CategorisationImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategoryScheme; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Codelist; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptScheme; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinition; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.Dataflow; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.Hierarchy; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinition; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.Metadataflow; +import com.epam.jsdmx.infomodel.sdmx30.MetadataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMap; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureMap; +import com.epam.jsdmx.infomodel.sdmx30.StructureMapImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.serializer.sdmx30.common.InMemoryDataLocation; + +import lombok.SneakyThrows; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class DataReaderTest { + + public static final String ARTEFACTS_JSON = "/deserialization.expected/json.json"; + public static final String ALL_ARTEFACTS_JSON = "/deserialization.expected/structures-all-artefacts.json"; + + public JsonStructureReader jsonStructureReader; + + @BeforeEach + void setup() { + jsonStructureReader = (JsonStructureReader) MaintainableArtifactsTestUtils.getStructureReader(); + } + + @Test + void readArtefacts() throws IOException { + InputStream resourceAsStream = DataReaderTest.class.getResourceAsStream(ARTEFACTS_JSON); + assert resourceAsStream != null; + byte[] structuresJsonBytes = resourceAsStream.readAllBytes(); + InMemoryDataLocation location = new InMemoryDataLocation(new String(structuresJsonBytes, StandardCharsets.UTF_8)); + ArtefactsImpl artefacts = jsonStructureReader.readAndClose(location); + CategorisationImpl expected = MaintainableArtifactsTestUtils.buildCategorisation(); + StructureMapImpl expectedStr = MaintainableArtifactsTestUtils.buildStructureMap(); + Set categorisations = Set.of(expected); + Set structureMaps = Set.of(expectedStr); + assertEquals(categorisations, artefacts.getCategorisations()); + assertEquals(structureMaps, artefacts.getStructureMaps()); + } + + @Test + void readAllArtefactsFromJson() throws IOException { + InputStream resourceAsStream = DataReaderTest.class.getResourceAsStream(ALL_ARTEFACTS_JSON); + assert resourceAsStream != null; + byte[] structuresJsonBytes = resourceAsStream.readAllBytes(); + InMemoryDataLocation location = new InMemoryDataLocation(new String(structuresJsonBytes, StandardCharsets.UTF_8)); + ArtefactsImpl artefacts = jsonStructureReader.readAndClose(location); + CategorisationImpl categorisation = MaintainableArtifactsTestUtils.buildCategorisation(); + StructureMapImpl structureMap = MaintainableArtifactsTestUtils.buildStructureMap(); + DataStructureDefinitionImpl dataStructureDefinition = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + dataStructureDefinition.setAttributeDescriptor(MaintainableArtifactsTestUtils.fillAttributeDescriptor()); + dataStructureDefinition.setDimensionDescriptor(MaintainableArtifactsTestUtils.fillDimensionDescriptor()); + dataStructureDefinition.setMeasureDescriptor(MaintainableArtifactsTestUtils.fillMeasureDescriptor()); + MetadataStructureDefinitionImpl metadataStructureDefinition = MaintainableArtifactsTestUtils.buildMetadataStructureDefinition(); + DataflowImpl dataflow = MaintainableArtifactsTestUtils.buildDataFlow(); + MetadataflowImpl metadataflow = MaintainableArtifactsTestUtils.buildMetadataFlow(); + RepresentationMapImpl representationMap = MaintainableArtifactsTestUtils.buildRepresentationMap(); + HierarchyImpl hierarchy = MaintainableArtifactsTestUtils.buildHierarchy(); + CodelistImpl codelist = MaintainableArtifactsTestUtils.buildCodeList(); + CategorySchemeImpl categoryScheme = MaintainableArtifactsTestUtils.buildCategoryScheme(); + ConceptSchemeImpl conceptScheme = MaintainableArtifactsTestUtils.buildConceptScheme(); + DataConstraintImpl dataConstraint = MaintainableArtifactsTestUtils.buildDataConstraint(); + + assertArtefacts(artefacts, categorisation, structureMap, dataStructureDefinition, metadataStructureDefinition, dataflow, metadataflow, + representationMap, hierarchy, codelist, categoryScheme, conceptScheme, dataConstraint + ); + } + + @SneakyThrows + private void assertArtefacts(ArtefactsImpl artefacts, + CategorisationImpl categorisation, + StructureMapImpl structureMap, + DataStructureDefinitionImpl dataStructureDefinition, + MetadataStructureDefinitionImpl metadataStructureDefinition, + DataflowImpl dataflow, + MetadataflowImpl metadataflow, + RepresentationMapImpl representationMap, + HierarchyImpl hierarchy, + CodelistImpl codelist, + CategorySchemeImpl categoryScheme, + ConceptSchemeImpl conceptScheme, + DataConstraintImpl dataConstraint) { + + Set categorisations = Set.of(categorisation); + Set structureMaps = Set.of(structureMap); + Set dataflowSet = Set.of(dataflow); + Set metadataflows = Set.of(metadataflow); + Set dataStructureDefinitions = Set.of(dataStructureDefinition); + Set metadataStructureDefinitions = Set.of(metadataStructureDefinition); + Set hierarchies = Set.of(hierarchy); + Set codelists = Set.of(codelist); + Set conceptSchemes = Set.of(conceptScheme); + Set categorySchemes = Set.of(categoryScheme); + Set representationMaps = Set.of(representationMap); + Set dataConstraintMaps = Set.of(dataConstraint); + ArtefactAssertion.assertThat(artefacts) + .hasCategorisation(categorisations) + .hasCategoryScheme(categorySchemes) + .hasCodeLists(codelists) + .hasDataFlows(dataflowSet) + .hasDSD(dataStructureDefinitions) + .hasMDSD(metadataStructureDefinitions) + .hasHierarchies(hierarchies) + .hasConceptSchemes(conceptSchemes) + .hasRepresentationMaps(representationMaps) + .hasStructureMaps(structureMaps) + .hasMetadataFlows(metadataflows) + .hasDataConstraint(dataConstraintMaps); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/DataStructureDefinitionReaderTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/DataStructureDefinitionReaderTest.java new file mode 100644 index 0000000..cd9087d --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/DataStructureDefinitionReaderTest.java @@ -0,0 +1,278 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptorImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class DataStructureDefinitionReaderTest extends BaseJsonReaderTest { + + public static final String DSD_JSON = "/serialization.expected/data-structure-definition.json"; + public static final String DSD_JSON_MES_FIRST = "/serialization.expected/data-structure-definition-order.json"; + public static final String DSD_JSON_NULL = "/deserialization.expected/data-structure-definition-components_null.json"; + public static final String DSD_JSON_COMPONENTS_EMPTY = "/deserialization.expected/data-structure-definition-components_empty.json"; + + public static final String DSD_ATTR_DESC_JSON = "/deserialization.expected/data-structure-definition-attr.json"; + public static final String DSD_ATTR_DESC_NULL = "/deserialization.expected/data-structure-definition-attr_null.json"; + public static final String DSD_ATTR_DESC_AND_NULL = "/deserialization.expected/data-structure-definition-attr_and_null.json"; + + public static final String DSD_DIM_DESC_JSON = "/deserialization.expected/data-structure-definition-dim.json"; + public static final String DSD_DIM_DESC_NULL = "/deserialization.expected/data-structure-definition-dim_null.json"; + public static final String DSD_DIM_DESC_AND_NULL = "/deserialization.expected/data-structure-definition-dim_and_null.json"; + + public static final String DSD_MEAS_DESC_JSON = "/deserialization.expected/data-structure-definition-meas.json"; + public static final String DSD_MEAS_DESC_NULL = "/deserialization.expected/data-structure-definition-meas_null.json"; + public static final String DSD_MEAS_DESC_AND_NULL = "/deserialization.expected/data-structure-definition-meas_and_null.json"; + public static final String DSD_FULL_JSON = "/deserialization.expected/data-structure-definition-full.json"; + public static final String ATTRIBUTE_DESCRIPTOR = "AttributeDescriptor"; + public static final String DIMENSION_DESCRIPTOR = "DimensionDescriptor"; + private static final String MEASURE_DESCRIPTOR = "MeasureDescriptor"; + + @InjectMocks + public DataStructureDefinitionReader dataStructureDefinitionReader; + + @Test + void readDataStructureDefinitionFromJsonTest() throws IOException { + //given + JsonParser parser = createParser(DSD_JSON); + + DataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + + //when + DataStructureDefinitionImpl actual = (DataStructureDefinitionImpl) dataStructureDefinitionReader.readAndClose(parser); + + //then + assertEquals(expected.getAnnotations(), actual.getAnnotations()); + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readDataStructureDefinitionWithAllDescriptorsFromJsonOrderTest() throws IOException { + //given + JsonParser parser = createParser(DSD_JSON_MES_FIRST); + DataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + expected.setAttributeDescriptor(MaintainableArtifactsTestUtils.fillAttributeDescriptor()); + expected.setDimensionDescriptor(MaintainableArtifactsTestUtils.fillDimensionDescriptor()); + expected.setMeasureDescriptor(MaintainableArtifactsTestUtils.fillMeasureDescriptor()); + + //when + DataStructureDefinitionImpl actual = (DataStructureDefinitionImpl) dataStructureDefinitionReader.readAndClose(parser); + + //then + assertEquals(expected.getAnnotations(), actual.getAnnotations()); + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readDataStructureDefinitionWithAttributeDescriptorFromJsonTest() throws IOException { + //given + JsonParser parser = createParser(DSD_ATTR_DESC_JSON); + DataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + expected.setAttributeDescriptor(MaintainableArtifactsTestUtils.fillAttributeDescriptor()); + DimensionDescriptorImpl dimensionDescriptor = new DimensionDescriptorImpl(); + dimensionDescriptor.setId(DIMENSION_DESCRIPTOR); + expected.setDimensionDescriptor(dimensionDescriptor); + MeasureDescriptorImpl measureDescriptor = new MeasureDescriptorImpl(); + measureDescriptor.setId(MEASURE_DESCRIPTOR); + expected.setMeasureDescriptor(measureDescriptor); + //when + DataStructureDefinitionImpl actual = (DataStructureDefinitionImpl) dataStructureDefinitionReader.readAndClose(parser); + + //then + assertEquals(expected.getAnnotations(), actual.getAnnotations()); + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readDataStructureDefinitionWithDimensionDescriptorFromJsonTest() throws IOException { + //given + JsonParser parser = createParser(DSD_DIM_DESC_JSON); + DataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + expected.setDimensionDescriptor(MaintainableArtifactsTestUtils.fillDimensionDescriptor()); + MeasureDescriptorImpl measureDescriptor = new MeasureDescriptorImpl(); + measureDescriptor.setId(MEASURE_DESCRIPTOR); + expected.setMeasureDescriptor(measureDescriptor); + AttributeDescriptorImpl attributeDescriptor = new AttributeDescriptorImpl(); + attributeDescriptor.setId(ATTRIBUTE_DESCRIPTOR); + expected.setAttributeDescriptor(attributeDescriptor); + //when + DataStructureDefinitionImpl actual = (DataStructureDefinitionImpl) dataStructureDefinitionReader.readAndClose(parser); + + //then + assertEquals(expected.getAnnotations(), actual.getAnnotations()); + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readDataStructureDefinitionWithMeasureDescriptorFromJsonTest() throws IOException { + //given + JsonParser parser = createParser(DSD_MEAS_DESC_JSON); + DataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + expected.setMeasureDescriptor(MaintainableArtifactsTestUtils.fillMeasureDescriptor()); + AttributeDescriptorImpl attributeDescriptor = new AttributeDescriptorImpl(); + attributeDescriptor.setId(ATTRIBUTE_DESCRIPTOR); + DimensionDescriptorImpl dimensionDescriptor = new DimensionDescriptorImpl(); + dimensionDescriptor.setId(DIMENSION_DESCRIPTOR); + expected.setAttributeDescriptor(attributeDescriptor); + expected.setDimensionDescriptor(dimensionDescriptor); + //when + DataStructureDefinitionImpl actual = (DataStructureDefinitionImpl) dataStructureDefinitionReader.readAndClose(parser); + + //then + assertEquals(expected.getAnnotations(), actual.getAnnotations()); + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readDataStructureDefinitionWithAllDescriptorsFromJsonTest() throws IOException { + //given + JsonParser parser = createParser(DSD_FULL_JSON); + DataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + expected.setAttributeDescriptor(MaintainableArtifactsTestUtils.fillAttributeDescriptor()); + expected.setDimensionDescriptor(MaintainableArtifactsTestUtils.fillDimensionDescriptor()); + expected.setMeasureDescriptor(MaintainableArtifactsTestUtils.fillMeasureDescriptor()); + + //when + DataStructureDefinitionImpl actual = (DataStructureDefinitionImpl) dataStructureDefinitionReader.readAndClose(parser); + + //then + assertEquals(expected.getAnnotations(), actual.getAnnotations()); + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readAttributeDescriptorsAndNull() throws IOException { + //given + JsonParser parser = createParser(DSD_ATTR_DESC_AND_NULL); + DataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + expected.setAttributeDescriptor(MaintainableArtifactsTestUtils.fillAttributeDescriptor()); + + //when + DataStructureDefinitionImpl actual = (DataStructureDefinitionImpl) dataStructureDefinitionReader.readAndClose(parser); + + //then + assertEquals(expected.getAnnotations(), actual.getAnnotations()); + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readDimDescriptorsAndNull() throws IOException { + //given + JsonParser parser = createParser(DSD_DIM_DESC_AND_NULL); + DataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + expected.setDimensionDescriptor(MaintainableArtifactsTestUtils.fillDimensionDescriptor()); + + //when + DataStructureDefinitionImpl actual = (DataStructureDefinitionImpl) dataStructureDefinitionReader.readAndClose(parser); + + //then + assertEquals(expected.getAnnotations(), actual.getAnnotations()); + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readMeasDescriptorsAndNull() throws IOException { + //given + JsonParser parser = createParser(DSD_MEAS_DESC_AND_NULL); + DataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + expected.setMeasureDescriptor(MaintainableArtifactsTestUtils.fillMeasureDescriptor()); + + //when + DataStructureDefinitionImpl actual = (DataStructureDefinitionImpl) dataStructureDefinitionReader.readAndClose(parser); + + //then + assertEquals(expected.getAnnotations(), actual.getAnnotations()); + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readAttributeDescriptorNull() throws IOException { + //given + JsonParser parser = createParser(DSD_ATTR_DESC_NULL); + DataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + expected.setDimensionDescriptor(MaintainableArtifactsTestUtils.fillDimensionDescriptor()); + expected.setMeasureDescriptor(MaintainableArtifactsTestUtils.fillMeasureDescriptor()); + + //when + DataStructureDefinitionImpl actual = (DataStructureDefinitionImpl) dataStructureDefinitionReader.readAndClose(parser); + + //then + assertEquals(expected.getAnnotations(), actual.getAnnotations()); + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readDimDescriptorNull() throws IOException { + //given + JsonParser parser = createParser(DSD_DIM_DESC_NULL); + DataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + expected.setAttributeDescriptor(MaintainableArtifactsTestUtils.fillAttributeDescriptor()); + expected.setMeasureDescriptor(MaintainableArtifactsTestUtils.fillMeasureDescriptor()); + + //when + DataStructureDefinitionImpl actual = (DataStructureDefinitionImpl) dataStructureDefinitionReader.readAndClose(parser); + + //then + assertEquals(expected.getAnnotations(), actual.getAnnotations()); + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readMeasDescriptorNull() throws IOException { + //given + JsonParser parser = createParser(DSD_MEAS_DESC_NULL); + DataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + expected.setDimensionDescriptor(MaintainableArtifactsTestUtils.fillDimensionDescriptor()); + expected.setAttributeDescriptor(MaintainableArtifactsTestUtils.fillAttributeDescriptor()); + + //when + DataStructureDefinitionImpl actual = (DataStructureDefinitionImpl) dataStructureDefinitionReader.readAndClose(parser); + + //then + assertEquals(expected.getAnnotations(), actual.getAnnotations()); + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readAllDescriptorNull() throws IOException { + //given + JsonParser parser = createParser(DSD_JSON_NULL); + DataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + //when + DataStructureDefinitionImpl actual = (DataStructureDefinitionImpl) dataStructureDefinitionReader.readAndClose(parser); + //then + assertEquals(expected.getAnnotations(), actual.getAnnotations()); + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readAllDescriptorEmpty() throws IOException { + //given + JsonParser parser = createParser(DSD_JSON_COMPONENTS_EMPTY); + DataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + AttributeDescriptorImpl attributeDescriptor = new AttributeDescriptorImpl(); + attributeDescriptor.setId(ATTRIBUTE_DESCRIPTOR); + DimensionDescriptorImpl dimensionDescriptor = new DimensionDescriptorImpl(); + dimensionDescriptor.setId(DIMENSION_DESCRIPTOR); + expected.setAttributeDescriptor(attributeDescriptor); + expected.setDimensionDescriptor(dimensionDescriptor); + MeasureDescriptorImpl measureDescriptor = new MeasureDescriptorImpl(); + measureDescriptor.setId(MEASURE_DESCRIPTOR); + expected.setMeasureDescriptor(measureDescriptor); + //when + DataStructureDefinitionImpl actual = (DataStructureDefinitionImpl) dataStructureDefinitionReader.readAndClose(parser); + //then + assertEquals(expected.getAnnotations(), actual.getAnnotations()); + assertTrue(expected.deepEquals(actual)); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/HierarchyReaderTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/HierarchyReaderTest.java new file mode 100644 index 0000000..e621a84 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/HierarchyReaderTest.java @@ -0,0 +1,58 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.HierarchyImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.json20.structure.TestUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class HierarchyReaderTest extends BaseJsonReaderTest { + + @InjectMocks + public HierarchyReader hierarchyReader; + + @Test + void readHierarchyFromJsonTest() throws IOException { + //given + JsonParser parser = createParser(TestUtils.HIERARCHY_JSON); + HierarchyImpl expected = MaintainableArtifactsTestUtils.buildHierarchy(); + + //when + HierarchyImpl actual = (HierarchyImpl) hierarchyReader.readAndClose(parser); + + //then + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readHierarchyFromJsonWithInsideHierarchyTest() throws IOException { + //given + JsonParser parser = createParser(TestUtils.HIERARCHY_HI_JSON); + + HierarchyImpl expected = MaintainableArtifactsTestUtils.buildHierarchyWithInnerHierarchy(); + + //when + HierarchyImpl actual = (HierarchyImpl) hierarchyReader.readAndClose(parser); + //then + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readHierarchyFromJsonWithInsideHierarchyAndLevelsTest() throws IOException { + //given + JsonParser parser = createParser("/deserialization.expected/hierarchy2.json"); + + //when + HierarchyImpl actual = (HierarchyImpl) hierarchyReader.readAndClose(parser); + //then + assertThat(actual).isNotNull(); + } + +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/MetadataFlowReaderTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/MetadataFlowReaderTest.java new file mode 100644 index 0000000..69c9d39 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/MetadataFlowReaderTest.java @@ -0,0 +1,49 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.Metadataflow; +import com.epam.jsdmx.infomodel.sdmx30.MetadataflowImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.json20.structure.TestUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class MetadataFlowReaderTest extends BaseJsonReaderTest { + + @InjectMocks + public MetadataFlowReader metadataFlowReader; + @InjectMocks + public DataFlowReader dataFlowReader; + + @Test + void testDataflow() throws IOException { + //given + JsonParser parser = createParser(TestUtils.DATA_FLOW_JSON); + DataflowImpl expected = MaintainableArtifactsTestUtils.buildDataFlow(); + + //when + DataflowImpl actual = (DataflowImpl) dataFlowReader.readAndClose(parser); + + //then + assertTrue(expected.deepEquals(actual)); + } + + @Test + void testMetaDataflow() throws IOException { + //given + JsonParser parser = createParser(TestUtils.METADATA_FLOW_JSON); + MetadataflowImpl expected = MaintainableArtifactsTestUtils.buildMetadataFlow(); + + //when + Metadataflow actual = (Metadataflow) metadataFlowReader.readAndClose(parser); + + //then + assertTrue(expected.deepEquals(actual)); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/MetadataStructureDefinitionReaderTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/MetadataStructureDefinitionReaderTest.java new file mode 100644 index 0000000..cf3cc9f --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/MetadataStructureDefinitionReaderTest.java @@ -0,0 +1,44 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinitionImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.json20.structure.TestUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class MetadataStructureDefinitionReaderTest extends BaseJsonReaderTest { + + @InjectMocks + public MetaDataStructureDefinitionReader metaDataStructureDefinitionReader; + + @Test + void readMetaDataStructureDefinitionFromJsonTest() throws IOException { + //given + JsonParser parser = createParser(TestUtils.METADATA_STRUCTURE_DEF_JSON); + MetadataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildMetadataStructureDefinition(); + + //when + MetadataStructureDefinitionImpl actual = (MetadataStructureDefinitionImpl) metaDataStructureDefinitionReader.readAndClose(parser); + + //then + assertTrue(expected.deepEquals(actual)); + } + + @Test + void readMetaDataStructureDefinitionFromJsonTestMultipleAttributes() throws IOException { + //given + JsonParser parser = createParser("/serialization.expected/metadata-structure-definition-multi-attributes.json"); + + MetadataStructureDefinitionImpl actual = (MetadataStructureDefinitionImpl) metaDataStructureDefinitionReader.readAndClose(parser); + + //then + assertThat(actual).isNotNull(); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/RepresentationMapReaderTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/RepresentationMapReaderTest.java new file mode 100644 index 0000000..4c1216f --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/RepresentationMapReaderTest.java @@ -0,0 +1,32 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static com.epam.jsdmx.json20.structure.TestUtils.REPRESENTATION_MAP_JSON; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; + +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonParser; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class RepresentationMapReaderTest extends BaseJsonReaderTest { + + @InjectMocks + public RepresentationMapReader representationMapReader; + + @Test + void readRepresentationMapFromJsonTest() throws IOException { + //given + JsonParser parser = createParser(REPRESENTATION_MAP_JSON); + RepresentationMapImpl expected = MaintainableArtifactsTestUtils.buildRepresentationMap(); + + //when + RepresentationMapImpl actual = (RepresentationMapImpl) representationMapReader.readAndClose(parser); + + //then + assertTrue(expected.deepEquals(actual)); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/StructureMapReaderTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/StructureMapReaderTest.java new file mode 100644 index 0000000..d1f86f7 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/reader/StructureMapReaderTest.java @@ -0,0 +1,128 @@ +package com.epam.jsdmx.json20.structure.reader; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.ComponentMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.DatePatternMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.FrequencyFormatMappingImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.ResolvePeriod; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureMap; +import com.epam.jsdmx.infomodel.sdmx30.StructureMapImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.json20.structure.TestUtils; +import com.epam.jsdmx.serializer.sdmx30.common.InMemoryDataLocation; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class StructureMapReaderTest { + + public JsonStructureReader jsonStructureReader; + + @BeforeEach + void setup() { + jsonStructureReader = (JsonStructureReader) MaintainableArtifactsTestUtils.getStructureReader(); + } + + @Test + void testStructureMap() throws IOException { + //given + InputStream resourceAsStream = DataReaderTest.class.getResourceAsStream(TestUtils.STRUCTURE_MAP_JSON); + assert resourceAsStream != null; + byte[] structuresJsonBytes = resourceAsStream.readAllBytes(); + InMemoryDataLocation location = new InMemoryDataLocation(new String(structuresJsonBytes, StandardCharsets.UTF_8)); + //when + ArtefactsImpl artefacts = jsonStructureReader.readAndClose(location); + StructureMapImpl expectedStr = MaintainableArtifactsTestUtils.buildStructureMap(); + Set structureMaps = Set.of(expectedStr); + //then + assertEquals(structureMaps, artefacts.getStructureMaps()); + } + + @Test + void testStructureMapList() throws IOException { + //given + InputStream resourceAsStream = DataReaderTest.class.getResourceAsStream(TestUtils.STRUCTURE_MAP_LIST_JSON); + assert resourceAsStream != null; + byte[] structuresJsonBytes = resourceAsStream.readAllBytes(); + InMemoryDataLocation location = new InMemoryDataLocation(new String(structuresJsonBytes, StandardCharsets.UTF_8)); + //when + ArtefactsImpl artefacts = jsonStructureReader.readAndClose(location); + StructureMap expectedStructure1 = MaintainableArtifactsTestUtils.buildStructureMap(); + StructureMap expectedStructure2 = buildStructureMap2(); + Set structureMaps = Set.of(expectedStructure1, expectedStructure2); + //then + assertEquals(structureMaps, artefacts.getStructureMaps()); + + } + + private StructureMap buildStructureMap2() { + StructureMapImpl structureMap = new StructureMapImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(structureMap); + structureMap.setId("STRUC_ID2"); + structureMap.setOrganizationId("QUANTHUB"); + structureMap.setSource(new MaintainableArtefactReference("DataFSource", "EPM", "3.0", StructureClassImpl.DATAFLOW)); + structureMap.setTarget(new MaintainableArtefactReference("DataFTarget", "EPM", "3.0", StructureClassImpl.DATAFLOW)); + fillComponentMap(structureMap); + fillDatePattern(structureMap); + return structureMap; + } + + void fillDatePattern(StructureMapImpl structureMap) { + DatePatternMapImpl datePatternMap = new DatePatternMapImpl(); + datePatternMap.setLocale("EN"); + datePatternMap.setSourcePattern("SOURCE"); + datePatternMap.setId("DP1"); + datePatternMap.setResolvePeriod(ResolvePeriod.MID_PERIOD); + FrequencyFormatMappingImpl frequencyFormatMapping1 = getFrequencyFormatMapping("CODE_1", "FR1"); + FrequencyFormatMappingImpl frequencyFormatMapping2 = getFrequencyFormatMapping("CODE_2", "FR2"); + datePatternMap.setMappedFrequencies(List.of(frequencyFormatMapping1, frequencyFormatMapping2)); + structureMap.setDatePatternMaps(List.of(datePatternMap)); + } + + private FrequencyFormatMappingImpl getFrequencyFormatMapping(String freqCode, String id) { + FrequencyFormatMappingImpl frequencyFormatMapping = new FrequencyFormatMappingImpl(); + frequencyFormatMapping.setFrequencyCode(freqCode); + frequencyFormatMapping.setDatePattern("2022-11"); + frequencyFormatMapping.setId(id); + return frequencyFormatMapping; + } + + void fillComponentMap(StructureMapImpl structureMap) { + ComponentMapImpl componentMapDP = new ComponentMapImpl(); + componentMapDP.setSource(List.of("CompMapDPS")); + componentMapDP.setTarget(List.of("CompMapDPT")); + IdentifiableArtefactReferenceImpl reference2 = new IdentifiableArtefactReferenceImpl( + "STRUC_ID2", + "QUANTHUB", + "1.2", + StructureClassImpl.DATE_PATTERN_MAP, + "DP1" + ); + componentMapDP.setRepresentationMap(reference2); + + ComponentMapImpl componentMaRep = new ComponentMapImpl(); + componentMaRep.setSource(List.of("CompMapRepS")); + componentMaRep.setTarget(List.of("CompMapRepT")); + IdentifiableArtefactReferenceImpl reference3 = new IdentifiableArtefactReferenceImpl( + "STRUC_ID2", + "QUANTHUB", + "1.2", + StructureClassImpl.REPRESENTATION_MAP, + "REPRES" + ); + componentMaRep.setRepresentationMap(reference3); + + structureMap.setComponentMaps(List.of(componentMapDP, componentMaRep)); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/AttributeListWriterJsonTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/AttributeListWriterJsonTest.java new file mode 100644 index 0000000..cd374f5 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/AttributeListWriterJsonTest.java @@ -0,0 +1,82 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import net.javacrumbs.jsonunit.JsonAssert; +import net.javacrumbs.jsonunit.core.Configuration; +import net.javacrumbs.jsonunit.core.Option; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +class AttributeListWriterJsonTest { + + public static final String ATTRIBUTE_LIST_JSON = "/serialization.expected/attribute-list.json"; + public static final String ATTRIBUTE_LIST_EMPTY_JSON = "/serialization.expected/attribute-list_empty.json"; + + @InjectMocks + public AttributeListWriter attributeListWriterJson; + @Spy + private AnnotableWriter annotableWriterSpy = MaintainableArtifactsTestUtils.getAnnotableWriter(); + @Spy + private ComponentWriter componentWriterSpy = MaintainableArtifactsTestUtils.getComponentWriter(); + @Spy + private ConceptRoleWriter conceptRoleWriterSpy = MaintainableArtifactsTestUtils.getConceptRoleWriter(); + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + } + + @Test + void writeAttributeListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + AttributeDescriptorImpl descriptor = MaintainableArtifactsTestUtils.fillAttributeDescriptor(); + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + jGenerator.writeStartObject(); + try (jGenerator) { + attributeListWriterJson.write(jGenerator, descriptor); + } + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(ATTRIBUTE_LIST_JSON, StandardCharsets.UTF_8); + + JsonAssert.assertJsonEquals(expected, actual, Configuration.empty().withOptions(Option.IGNORING_EXTRA_FIELDS)); + } + + @Test + void writeEmptyAttributeListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + jGenerator.writeStartObject(); + try (jGenerator) { + attributeListWriterJson.write(jGenerator, null); + } + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(ATTRIBUTE_LIST_EMPTY_JSON, StandardCharsets.UTF_8); + System.out.println(expected); + JsonAssert.assertJsonEquals(expected, actual, Configuration.empty().withOptions(Option.IGNORING_EXTRA_FIELDS)); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/BaseJsonWriterTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/BaseJsonWriterTest.java new file mode 100644 index 0000000..16d625f --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/BaseJsonWriterTest.java @@ -0,0 +1,185 @@ +package com.epam.jsdmx.json20.structure.writer; + +import static com.epam.jsdmx.json20.structure.TestUtils.AGENCY_SCHEME_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.CATEGORY_SCHEME_MAP_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.CONCEPT_SCHEME_MAP_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.DATA_CONSUMER_SCHEME_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.DATA_PROVIDER_SCHEME_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.GEOCODELIST_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.GEOGRIDCODELIST_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.HIERARCHY_ASSOCIATION_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.METADATA_CONSTRAINT_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.METADATA_PROVIDER_SCHEME_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.METADATA_PROVISION_AGREEMENT_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.ORGANISATION_SCHEME_MAP_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.ORGANISATION_UNIT_SCHEME_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.PROCESS_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.PROVISION_AGREEMENT_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.REPORTING_TAXONOMY_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.REPORTING_TAXONOMY_MAP_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.VALUE_LIST_JSON; +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.stream.Stream; + +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; +import com.epam.jsdmx.serializer.common.TimeDimensionLocalRepresentationAdapter; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultReferenceAdapter; + +import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +class BaseJsonWriterTest { + + @Spy + private ReferenceAdapter referenceAdapter = MaintainableArtifactsTestUtils.getUrnAdapter(); + @Spy + private TimeDimensionLocalRepresentationAdapter dsdAdapter = MaintainableArtifactsTestUtils.getDsdAdapter(); + @Spy + private RepresentationWriter representationWriter = MaintainableArtifactsTestUtils.getRepresentationWriter(); + @Spy + private MemberSelectionWriter memberSelectionWriter = MaintainableArtifactsTestUtils.getMemberSelectionWriter(); + @Spy + private VersionableWriter versionableWriterSpy = MaintainableArtifactsTestUtils.getVersionableWriter(); + @Spy + private LinksWriter linksWriterSpy = MaintainableArtifactsTestUtils.getLinksWriter(); + @Spy + private OrganisationWriter organisationWriter = MaintainableArtifactsTestUtils.getOrganisationWriter(); + @Spy + private AnnotableWriter annotableWriter = MaintainableArtifactsTestUtils.getAnnotableWriter(); + @Spy + private NameableWriter nameableWriter = MaintainableArtifactsTestUtils.getNameableWriter(); + @Spy + private CodeWriterImpl codeWriter = MaintainableArtifactsTestUtils.getCodeImplWriter(); + @Spy + private CodelistExtensionWriter extensionWriter = MaintainableArtifactsTestUtils.getCodelistExtensionWriter(); + @Spy + private IdentifiableWriter identifiableWriter = MaintainableArtifactsTestUtils.getIdentifiableWriter(); + + private static Stream testArtefactWriters() { + + ReferenceAdapter referenceAdapter = new DefaultReferenceAdapter(); + ItemMapWriter itemMapWriter = new ItemMapWriter(referenceAdapter); + LinksWriter linksWriter = new LinksWriter(referenceAdapter); + AnnotableWriter annotableWriter = new AnnotableWriter(linksWriter); + IdentifiableWriter identifiableWriter = new IdentifiableWriter(annotableWriter); + NameableWriter nameableWriter = new NameableWriter(identifiableWriter); + VersionableWriter versionableWriter = new VersionableWriter(nameableWriter); + ContactsWriter contactsWriter = new ContactsWriter(); + OrganisationWriter organisationWriter = new OrganisationWriter(contactsWriter, nameableWriter); + DateTimeWriter dateTimeWriter = new DateTimeWriter(); + MemberSelectionWriter memberSelectionWriter = new MemberSelectionWriter(dateTimeWriter); + AgencySchemeWriter agencySchemeWriter = new AgencySchemeWriter(versionableWriter, linksWriter, organisationWriter); + CategorySchemeMapWriter categorySchemeMapWriter = new CategorySchemeMapWriter(versionableWriter, linksWriter, annotableWriter, itemMapWriter); + ConceptSchemeMapWriter conceptSchemeMapWriter = new ConceptSchemeMapWriter(versionableWriter, linksWriter, annotableWriter, itemMapWriter); + DataConsumerSchemeWriter dataConsumerSchemeWriter = new DataConsumerSchemeWriter(versionableWriter, linksWriter, organisationWriter); + DataProviderSchemeWriter dataProviderSchemeWriter = new DataProviderSchemeWriter(versionableWriter, linksWriter, organisationWriter); + HierarchyAssociationWriter hierarchyAssociationWriter = new HierarchyAssociationWriter(versionableWriter, linksWriter); + MetadataConstraintWriter metadataConstraintWriter = new MetadataConstraintWriter( + versionableWriter, + linksWriter, + memberSelectionWriter, + referenceAdapter + ); + MetadataProviderSchemeWriter metadataProviderSchemeWriter = new MetadataProviderSchemeWriter(versionableWriter, linksWriter, organisationWriter); + MetadataProvisionAgreementWriter metadataProvisionAgreementWriter = new MetadataProvisionAgreementWriter( + versionableWriter, + linksWriter, + referenceAdapter + ); + OrganisationSchemeMapWriter organisationSchemeMapWriter = new OrganisationSchemeMapWriter( + versionableWriter, + linksWriter, + annotableWriter, + itemMapWriter + ); + ProcessWriter processWriter = new ProcessWriter(versionableWriter, linksWriter, nameableWriter, annotableWriter, identifiableWriter); + ProvisionAgreementWriter provisionAgreementWriter = new ProvisionAgreementWriter(versionableWriter, linksWriter, referenceAdapter); + ReportingTaxonomyMapWriter reportingTaxonomyMapWriter = new ReportingTaxonomyMapWriter(versionableWriter, linksWriter, annotableWriter, itemMapWriter); + ReportingTaxonomyWriter reportingTaxonomyWriter = new ReportingTaxonomyWriter(versionableWriter, linksWriter, nameableWriter, referenceAdapter); + ValueListWriter valueListWriter = new ValueListWriter(versionableWriter, linksWriter, annotableWriter); + OrganisationUnitSchemeWriter organisationUnitSchemeWriter = new OrganisationUnitSchemeWriter(versionableWriter, linksWriter, organisationWriter); + GeoFeatureSetCodeWriter codeWriter = new GeoFeatureSetCodeWriter(); + CodelistExtensionWriter codelistExtensionWriter = new CodelistExtensionWriter(referenceAdapter); + GeographicCodelistWriter geographicCodelistWriter = new GeographicCodelistWriter( + versionableWriter, + linksWriter, + codeWriter, + codelistExtensionWriter, + nameableWriter + ); + GridCodeWriter gridCodeWriter = new GridCodeWriter(); + GeoGridCodelistWriter geoGridCodelistWriter = new GeoGridCodelistWriter( + versionableWriter, + linksWriter, + codelistExtensionWriter, + gridCodeWriter, + nameableWriter + ); + + return Stream.of( + Arguments.of( + ORGANISATION_UNIT_SCHEME_JSON, + organisationUnitSchemeWriter, + MaintainableArtifactsTestUtils.buildOrganisationUnitScheme() + ), + Arguments.of(AGENCY_SCHEME_JSON, agencySchemeWriter, MaintainableArtifactsTestUtils.buildAgencyScheme()), + Arguments.of(CATEGORY_SCHEME_MAP_JSON, categorySchemeMapWriter, MaintainableArtifactsTestUtils.buildCategorySchemeMap()), + Arguments.of(CONCEPT_SCHEME_MAP_JSON, conceptSchemeMapWriter, MaintainableArtifactsTestUtils.buildConceptSchemeMap()), + Arguments.of(DATA_CONSUMER_SCHEME_JSON, dataConsumerSchemeWriter, MaintainableArtifactsTestUtils.buildDataConsumerScheme()), + Arguments.of(DATA_PROVIDER_SCHEME_JSON, dataProviderSchemeWriter, MaintainableArtifactsTestUtils.buildDataProviderScheme()), + Arguments.of(HIERARCHY_ASSOCIATION_JSON, hierarchyAssociationWriter, MaintainableArtifactsTestUtils.buildHierarchyAssociation()), + Arguments.of(METADATA_CONSTRAINT_JSON, metadataConstraintWriter, MaintainableArtifactsTestUtils.buildMetadataConstraint(true)), + Arguments.of(METADATA_PROVIDER_SCHEME_JSON, metadataProviderSchemeWriter, MaintainableArtifactsTestUtils.buildMetadataProviderScheme()), + Arguments.of(METADATA_PROVISION_AGREEMENT_JSON, metadataProvisionAgreementWriter, MaintainableArtifactsTestUtils.buildMetadataProvisionAgreement()), + Arguments.of(ORGANISATION_SCHEME_MAP_JSON, organisationSchemeMapWriter, MaintainableArtifactsTestUtils.buildOrganisationSchemeMap()), + Arguments.of(PROCESS_JSON, processWriter, MaintainableArtifactsTestUtils.buildProcess()), + Arguments.of(PROVISION_AGREEMENT_JSON, provisionAgreementWriter, MaintainableArtifactsTestUtils.buildProvisionAgreement()), + Arguments.of(REPORTING_TAXONOMY_MAP_JSON, reportingTaxonomyMapWriter, MaintainableArtifactsTestUtils.buildReportingTaxonomyMap()), + Arguments.of(REPORTING_TAXONOMY_JSON, reportingTaxonomyWriter, MaintainableArtifactsTestUtils.buildReportingTaxonomy()), + Arguments.of(VALUE_LIST_JSON, valueListWriter, MaintainableArtifactsTestUtils.buildValueList()), + Arguments.of(GEOCODELIST_JSON, geographicCodelistWriter, MaintainableArtifactsTestUtils.buildGeographicCodelist()), + Arguments.of(GEOGRIDCODELIST_JSON, geoGridCodelistWriter, MaintainableArtifactsTestUtils.buildGeoGridCodelist()) + ); + } + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + } + + public JsonGenerator createJsonGenerator(ByteArrayOutputStream stream) throws IOException { + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + return jGenerator; + } + + @ParameterizedTest + @MethodSource("testArtefactWriters") + void writeToJson(String path, MaintainableWriter writer, T artefact) throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + //when + writer.writeAndClose(createJsonGenerator(stream), artefact); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(path, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/CategorisationWriterTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/CategorisationWriterTest.java new file mode 100644 index 0000000..42f9b68 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/CategorisationWriterTest.java @@ -0,0 +1,39 @@ +package com.epam.jsdmx.json20.structure.writer; + + +import static com.epam.jsdmx.json20.structure.TestUtils.CATEGORISATION_JSON; +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.Categorisation; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class CategorisationWriterTest extends BaseJsonWriterTest { + + @InjectMocks + public CategorisationWriter categorisationWriter; + + @Test + void writeCategorisationToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Categorisation categorisation = MaintainableArtifactsTestUtils.buildCategorisation(); + + //when + categorisationWriter.writeAndClose(createJsonGenerator(stream), categorisation); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + MaintainableArtifactsTestUtils.assertMaintainableArtefactsInJson(actual); + String expected = IOUtils.resourceToString(CATEGORISATION_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/CategorySchemeWriterTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/CategorySchemeWriterTest.java new file mode 100644 index 0000000..1ff2dbb --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/CategorySchemeWriterTest.java @@ -0,0 +1,38 @@ +package com.epam.jsdmx.json20.structure.writer; + +import static com.epam.jsdmx.json20.structure.TestUtils.CATEGORY_SCHEMA_JSON; +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class CategorySchemeWriterTest extends BaseJsonWriterTest { + + @InjectMocks + public CategorySchemeWriter categorySchemeWriter; + + @Test + void writeCategorySchemeToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + CategorySchemeImpl categoryScheme = MaintainableArtifactsTestUtils.buildCategoryScheme(); + + //when + categorySchemeWriter.writeAndClose(createJsonGenerator(stream), categoryScheme); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + MaintainableArtifactsTestUtils.assertMaintainableArtefactsInJson(actual); + String expected = IOUtils.resourceToString(CATEGORY_SCHEMA_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/CodelistWriterTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/CodelistWriterTest.java new file mode 100644 index 0000000..a634ea2 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/CodelistWriterTest.java @@ -0,0 +1,38 @@ +package com.epam.jsdmx.json20.structure.writer; + +import static com.epam.jsdmx.json20.structure.TestUtils.CODE_LIST_JSON; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.Codelist; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import net.javacrumbs.jsonunit.JsonAssert; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class CodelistWriterTest extends BaseJsonWriterTest { + + @InjectMocks + public CodelistWriter codeListWriter; + + @Test + void writeCodeListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Codelist codelist = MaintainableArtifactsTestUtils.buildCodeList(); + + //when + codeListWriter.writeAndClose(createJsonGenerator(stream), codelist); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + MaintainableArtifactsTestUtils.assertMaintainableArtefactsInJson(actual); + String expected = IOUtils.resourceToString(CODE_LIST_JSON, StandardCharsets.UTF_8); + + JsonAssert.assertJsonEquals(expected, actual); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/ConceptSchemeWriterTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/ConceptSchemeWriterTest.java new file mode 100644 index 0000000..60f7bad --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/ConceptSchemeWriterTest.java @@ -0,0 +1,39 @@ +package com.epam.jsdmx.json20.structure.writer; + +import static com.epam.jsdmx.json20.structure.TestUtils.CONCEPT_SCHEMA_JSON; +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class ConceptSchemeWriterTest extends BaseJsonWriterTest { + + @InjectMocks + public ConceptSchemeWriter conceptSchemeWriter; + + @Test + void writeConceptSchemeToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + ConceptSchemeImpl conceptScheme = MaintainableArtifactsTestUtils.buildConceptScheme(); + + //when + conceptSchemeWriter.writeAndClose(createJsonGenerator(stream), conceptScheme); + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(CONCEPT_SCHEMA_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } + +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/DataConstraintWriterTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/DataConstraintWriterTest.java new file mode 100644 index 0000000..dce2c10 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/DataConstraintWriterTest.java @@ -0,0 +1,64 @@ +package com.epam.jsdmx.json20.structure.writer; + +import static com.epam.jsdmx.json20.structure.TestUtils.DATA_CONSTRAINT_EMPTY_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.DATA_CONSTRAINT_JSON; +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.DataConstraintImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Spy; + +class DataConstraintWriterTest extends BaseJsonWriterTest { + + @InjectMocks + public DataConstraintWriter dataConstraintWriter; + @Spy + private CubeRegionWriter cubeRegionWriterSpy = MaintainableArtifactsTestUtils.getCubeRegionWriter(); + @Spy + private DataKeySetsWriter dataKeySetsWriter = MaintainableArtifactsTestUtils.getDataKeySetsWriter(); + + @Test + void writeDataConstraintToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + DataConstraintImpl dataConstraint = MaintainableArtifactsTestUtils.buildDataConstraint(); + + //when + dataConstraintWriter.writeAndClose(createJsonGenerator(stream), dataConstraint); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(DATA_CONSTRAINT_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } + + @Test + void writeDataConstraintEmptyToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + DataConstraintImpl dataConstraint = MaintainableArtifactsTestUtils.buildDataConstraint(); + dataConstraint.setDataContentKeys(List.of()); + dataConstraint.setCubeRegions(List.of()); + dataConstraint.setReleaseCalendar(null); + + //when + dataConstraintWriter.writeAndClose(createJsonGenerator(stream), dataConstraint); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(DATA_CONSTRAINT_EMPTY_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } + +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/DataStructureDefinitionWriterTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/DataStructureDefinitionWriterTest.java new file mode 100644 index 0000000..696cbd9 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/DataStructureDefinitionWriterTest.java @@ -0,0 +1,46 @@ +package com.epam.jsdmx.json20.structure.writer; + +import static com.epam.jsdmx.json20.structure.TestUtils.DATA_STRUCTURE_DEFINITION_JSON; +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Spy; + +class DataStructureDefinitionWriterTest extends BaseJsonWriterTest { + + @InjectMocks + public DataStructureDefinitionWriter dataStructureDefinitionWriter; + @Spy + private AttributeListWriter attributeListWriterSpy = MaintainableArtifactsTestUtils.getAttributeListWriter(); + @Spy + private DimensionListWriter dimensionListWriterSpy = MaintainableArtifactsTestUtils.getDimensionListWriter(); + @Spy + private MeasureListWriter measureListWriterSpy = MaintainableArtifactsTestUtils.getMeasureListWriter(); + + @Test + void writeDataStructureDefinitionToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + DataStructureDefinitionImpl dataStructureDefinition = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + + //when + dataStructureDefinitionWriter.writeAndClose(createJsonGenerator(stream), dataStructureDefinition); + String actual = stream.toString(StandardCharsets.UTF_8); + + System.out.println(actual); + //then + String expected = IOUtils.resourceToString(DATA_STRUCTURE_DEFINITION_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } + +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/DimensionListWriterJsonTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/DimensionListWriterJsonTest.java new file mode 100644 index 0000000..ac656a5 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/DimensionListWriterJsonTest.java @@ -0,0 +1,82 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptorImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import net.javacrumbs.jsonunit.JsonAssert; +import net.javacrumbs.jsonunit.core.Configuration; +import net.javacrumbs.jsonunit.core.Option; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +class DimensionListWriterJsonTest { + + public static final String DIMENSION_LIST_JSON = "/serialization.expected/dimension-list.json"; + public static final String DIMENSION_LIST_EMPTY_JSON = "/serialization.expected/dimension-list_empty.json"; + + @InjectMocks + public DimensionListWriter dimensionListWriterJson; + @Spy + private AnnotableWriter annotableWriterSpy = MaintainableArtifactsTestUtils.getAnnotableWriter(); + @Spy + private ComponentWriter componentWriterSpy = MaintainableArtifactsTestUtils.getComponentWriter(); + @Spy + private ConceptRoleWriter conceptRoleWriterSpy = MaintainableArtifactsTestUtils.getConceptRoleWriter(); + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + } + + @Test + void writeDimensionListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + DimensionDescriptorImpl descriptor = MaintainableArtifactsTestUtils.fillDimensionDescriptor(); + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + jGenerator.writeStartObject(); + try (jGenerator) { + dimensionListWriterJson.write(jGenerator, descriptor); + } + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(DIMENSION_LIST_JSON, StandardCharsets.UTF_8); + System.out.println(expected); + JsonAssert.assertJsonEquals(expected, actual, Configuration.empty().withOptions(Option.IGNORING_EXTRA_FIELDS)); + } + + @Test + void writeEmptyDimensionListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + jGenerator.writeStartObject(); + try (jGenerator) { + dimensionListWriterJson.write(jGenerator, null); + } + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(DIMENSION_LIST_EMPTY_JSON, StandardCharsets.UTF_8); + System.out.println(expected); + JsonAssert.assertJsonEquals(expected, actual, Configuration.empty().withOptions(Option.IGNORING_EXTRA_FIELDS)); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/GroupDimensionListWriterJsonTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/GroupDimensionListWriterJsonTest.java new file mode 100644 index 0000000..bb47de4 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/GroupDimensionListWriterJsonTest.java @@ -0,0 +1,60 @@ +package com.epam.jsdmx.json20.structure.writer; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.GroupDimensionDescriptor; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import net.javacrumbs.jsonunit.JsonAssert; +import net.javacrumbs.jsonunit.core.Configuration; +import net.javacrumbs.jsonunit.core.Option; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +class GroupDimensionListWriterJsonTest { + + public static final String GROUP_DIMENSION_LIST_JSON = "/serialization.expected/group-dimension-list.json"; + + @InjectMocks + public GroupDimensionListWriter groupDimensionListWriter; + @Spy + private IdentifiableWriter identifiableWriter = MaintainableArtifactsTestUtils.getIdentifiableWriter(); + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + } + + @Test + void writeDimensionListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + List descriptors = MaintainableArtifactsTestUtils.fillListGroupDimensionDescriptor().stream() + .map(a -> (GroupDimensionDescriptor) a) + .collect(Collectors.toList()); + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + jGenerator.writeStartObject(); + try (jGenerator) { + groupDimensionListWriter.write(jGenerator, descriptors); + } + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(GROUP_DIMENSION_LIST_JSON, StandardCharsets.UTF_8); + + JsonAssert.assertJsonEquals(expected, actual, Configuration.empty().withOptions(Option.IGNORING_EXTRA_FIELDS)); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/HierarchyWriterTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/HierarchyWriterTest.java new file mode 100644 index 0000000..394bf26 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/HierarchyWriterTest.java @@ -0,0 +1,55 @@ +package com.epam.jsdmx.json20.structure.writer; + +import static com.epam.jsdmx.json20.structure.TestUtils.HIERARCHY_HI_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.HIERARCHY_JSON; +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.Hierarchy; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class HierarchyWriterTest extends BaseJsonWriterTest { + + @InjectMocks + public HierarchyWriter hierarchyWriter; + + @Test + void writeHierarchyToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Hierarchy hierarchy = MaintainableArtifactsTestUtils.buildHierarchy(); + + //when + hierarchyWriter.writeAndClose(createJsonGenerator(stream), hierarchy); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(HIERARCHY_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } + + @Test + void writeHierarchyWithInnerHierarchyToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Hierarchy hierarchy = MaintainableArtifactsTestUtils.buildHierarchyWithInnerHierarchy(); + + //when + hierarchyWriter.writeAndClose(createJsonGenerator(stream), hierarchy); + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(HIERARCHY_HI_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/JsonStructureWriterTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/JsonStructureWriterTest.java new file mode 100644 index 0000000..001c1b2 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/JsonStructureWriterTest.java @@ -0,0 +1,209 @@ +package com.epam.jsdmx.json20.structure.writer; + +import static com.epam.jsdmx.json20.structure.writer.StructureUtils.SCHEMA; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayOutputStream; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.TreeSet; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorisationImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptScheme; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultHeaderProvider; +import com.epam.jsdmx.serializer.sdmx30.common.Header; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; +import net.javacrumbs.jsonunit.JsonAssert; +import net.javacrumbs.jsonunit.core.Option; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class JsonStructureWriterTest { + + public static final String STRUCTURE_JSON = "/serialization.expected/structure.json"; + public static final String EMPTY_STRUCTURE_JSON = "/serialization.expected/empty-structure.json"; + private final ObjectMapper objectMapper = new ObjectMapper(); + private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + private final DefaultHeaderProvider defaultHeaderProvider = mock(DefaultHeaderProvider.class); + private JsonStructureWriter jsonStructureWriter; + + @BeforeEach + @SneakyThrows + void setup() { + jsonStructureWriter = MaintainableArtifactsTestUtils.createStructureWriter(outputStream, objectMapper, defaultHeaderProvider); + when(defaultHeaderProvider.provide()).thenReturn(buildHeader()); + } + + @SneakyThrows + private Header buildHeader() { + Header header = new Header(); + header.setSchema(new URI(SCHEMA)); + header.setId("IDREF7553"); + header.setContentLanguages(List.of(Locale.ENGLISH)); + header.setTest(false); + header.setPrepared(Instant.parse("2022-04-03T15:35:01Z")); + header.setSender(buildParty()); + return header; + } + + private Party buildParty() { + Party party = new Party(); + party.setId("unknown"); + return party; + } + + @Test + void writeArtefactsToJson() throws Exception { + ArtefactsImpl artefacts = new ArtefactsImpl(); + fillCategorisation(artefacts); + fillCategoryScheme(artefacts); + fillConceptScheme(artefacts); + fillDataFlow(artefacts); + fillCodeList(artefacts); + fillDSD(artefacts); + fillHierarchy(artefacts); + fillMetadataFlow(artefacts); + fillMDSD(artefacts); + fillRepresentationMap(artefacts); + jsonStructureWriter.write(artefacts); + String actual = outputStream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(STRUCTURE_JSON, StandardCharsets.UTF_8); + JsonAssert.assertJsonEquals(expected, actual, JsonAssert.whenIgnoringPaths("meta").withOptions(Option.IGNORING_ARRAY_ORDER)); + } + + @Test + void writeEmptyArtefactsToJson() throws Exception { + + ArtefactsImpl artefacts = new ArtefactsImpl(); + jsonStructureWriter.write(artefacts); + String actual = outputStream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(EMPTY_STRUCTURE_JSON, StandardCharsets.UTF_8); + System.out.println(actual); + System.out.println(expected); + JsonAssert.assertJsonEquals(expected, actual, JsonAssert.whenIgnoringPaths("meta")); + } + + private void fillCategoryScheme(ArtefactsImpl artefacts) { + CategorySchemeImpl categoryScheme = new CategorySchemeImpl(); + categoryScheme.setId("CS1"); + categoryScheme.setVersion(Version.createFromString("1.0")); + artefacts.setCategorySchemes(new HashSet<>(Set.of(categoryScheme))); + } + + private void fillMDSD(ArtefactsImpl artefacts) { + MetadataStructureDefinitionImpl metadataStructureDefinition = new MetadataStructureDefinitionImpl(); + metadataStructureDefinition.setId("MDSD1"); + metadataStructureDefinition.setVersion(Version.createFromString("1.0")); + artefacts.setMetadataStructureDefinitions(new HashSet<>(Set.of(metadataStructureDefinition))); + } + + private void fillDataFlow(ArtefactsImpl artefacts) { + DataflowImpl dataflow = new DataflowImpl(); + dataflow.setVersion(Version.createFromString("1.0")); + dataflow.setId("DF1"); + artefacts.setDataflows(new HashSet<>(Set.of(dataflow))); + } + + private void fillConceptScheme(ArtefactsImpl artefacts) { + ConceptSchemeImpl conceptScheme = new ConceptSchemeImpl(); + conceptScheme.setId("CS1"); + conceptScheme.setVersion(Version.createFromString("1.0")); + ConceptSchemeImpl conceptSchemeSec = new ConceptSchemeImpl(); + conceptSchemeSec.setId("CS2"); + conceptSchemeSec.setVersion(Version.createFromString("1.0")); + Set sortedSet = new TreeSet<>(Comparator.comparing(IdentifiableArtefact::getId)); + sortedSet.add(conceptScheme); + sortedSet.add(conceptSchemeSec); + artefacts.setConceptSchemes(sortedSet); + } + + private void fillCategorisation(ArtefactsImpl artefacts) { + CategorisationImpl categorisation = new CategorisationImpl(); + IdentifiableArtefactReferenceImpl structureItemReference = new IdentifiableArtefactReferenceImpl("ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.CATEGORY, + "CAT_TARGET" + ); + + categorisation.setCategorizedBy(structureItemReference); + IdentifiableArtefactReferenceImpl structureReference = new IdentifiableArtefactReferenceImpl("ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.CATEGORISATION, + "CAT_SOURCE" + ); + categorisation.setCategorizedArtefact(structureReference); + categorisation.setId("catid"); + categorisation.setVersion(Version.createFromString("1.0")); + categorisation.setDescription(new InternationalString("categ")); + categorisation.setOrganizationId("EPM"); + artefacts.setCategorisations(new HashSet<>(Set.of(categorisation))); + } + + private void fillCodeList(ArtefactsImpl artefacts) { + CodelistImpl codeList = new CodelistImpl(); + codeList.setId("CL1"); + codeList.setVersion(Version.createFromString("1.0")); + artefacts.setCodelists(new HashSet<>(Set.of(codeList))); + } + + private void fillDSD(ArtefactsImpl artefacts) { + DataStructureDefinitionImpl dataStructureDefinition = new DataStructureDefinitionImpl(); + dataStructureDefinition.setId("DSD1"); + dataStructureDefinition.setVersion(Version.createFromString("1.0")); + artefacts.setDataStructures(new HashSet<>(Set.of(dataStructureDefinition))); + } + + private void fillHierarchy(ArtefactsImpl artefacts) { + HierarchyImpl hierarchy = new HierarchyImpl(); + hierarchy.setId("Hi1"); + hierarchy.setVersion(Version.createFromString("1.0")); + artefacts.setHierarchies(new HashSet<>(Set.of(hierarchy))); + } + + private void fillMetadataFlow(ArtefactsImpl artefacts) { + MetadataflowImpl metadataflow = new MetadataflowImpl(); + metadataflow.setId("MF1"); + metadataflow.setVersion(Version.createFromString("1.0")); + artefacts.setMetadataflows(new HashSet<>(Set.of(metadataflow))); + } + + private void fillRepresentationMap(ArtefactsImpl artefacts) { + RepresentationMapImpl representationMap = new RepresentationMapImpl(); + representationMap.setId("RM1"); + representationMap.setVersion(Version.createFromString("1.0")); + artefacts.setRepresentationMaps(new HashSet<>(Set.of(representationMap))); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/MeasureListWriterJsonTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/MeasureListWriterJsonTest.java new file mode 100644 index 0000000..4727e47 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/MeasureListWriterJsonTest.java @@ -0,0 +1,78 @@ +package com.epam.jsdmx.json20.structure.writer; + +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptorImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +class MeasureListWriterJsonTest { + + public static final String MEASURE_LIST_JSON = "/serialization.expected/measure-list.json"; + public static final String MEASURE_LIST_EMPTY_JSON = "/serialization.expected/measure-list_empty.json"; + @InjectMocks + public MeasureListWriter measureListWriterJson; + @Spy + private AnnotableWriter annotableWriterSpy = MaintainableArtifactsTestUtils.getAnnotableWriter(); + @Spy + private ComponentWriter componentWriterSpy = MaintainableArtifactsTestUtils.getComponentWriter(); + @Spy + private ConceptRoleWriter conceptRoleWriterSpy = MaintainableArtifactsTestUtils.getConceptRoleWriter(); + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + } + + @Test + void writeMeasureListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + MeasureDescriptorImpl descriptor = MaintainableArtifactsTestUtils.fillMeasureDescriptor(); + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + jGenerator.writeStartObject(); + try (jGenerator) { + measureListWriterJson.write(jGenerator, descriptor); + } + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(MEASURE_LIST_JSON, StandardCharsets.UTF_8); + assertJsonEquals(expected, actual); + } + + @Test + void writeEmptyMeasureListToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + jGenerator.writeStartObject(); + try (jGenerator) { + measureListWriterJson.write(jGenerator, null); + } + String actual = stream.toString(StandardCharsets.UTF_8); + System.out.println(actual); + + //then + String expected = IOUtils.resourceToString(MEASURE_LIST_EMPTY_JSON, StandardCharsets.UTF_8); + assertJsonEquals(expected, actual); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/MetaDataStructureDefinitionWriterTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/MetaDataStructureDefinitionWriterTest.java new file mode 100644 index 0000000..dc4cb1e --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/MetaDataStructureDefinitionWriterTest.java @@ -0,0 +1,40 @@ +package com.epam.jsdmx.json20.structure.writer; + +import static com.epam.jsdmx.json20.structure.TestUtils.METADATA_STRUCTURE_DEF_JSON; +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinition; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Spy; + +class MetaDataStructureDefinitionWriterTest extends BaseJsonWriterTest { + + @InjectMocks + public MetadataStructureDefinitionWriter metadataStructureDefinitionWriter; + @Spy + private ComponentWriter componentWriter = MaintainableArtifactsTestUtils.getComponentWriter(); + + @Test + void writeMetadataStructureDefinition() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + MetadataStructureDefinition metadataStructureDefinitionMock = MaintainableArtifactsTestUtils.buildMetadataStructureDefinition(); + + //when + metadataStructureDefinitionWriter.writeAndClose(createJsonGenerator(stream), metadataStructureDefinitionMock); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(METADATA_STRUCTURE_DEF_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/MetadataflowWriterTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/MetadataflowWriterTest.java new file mode 100644 index 0000000..bb2ff4b --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/MetadataflowWriterTest.java @@ -0,0 +1,68 @@ +package com.epam.jsdmx.json20.structure.writer; + +import static com.epam.jsdmx.json20.structure.TestUtils.DATA_FLOW_JSON; +import static com.epam.jsdmx.json20.structure.TestUtils.METADATA_FLOW_JSON; +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.AnnotationImpl; +import com.epam.jsdmx.infomodel.sdmx30.Dataflow; +import com.epam.jsdmx.infomodel.sdmx30.InternationalUri; +import com.epam.jsdmx.infomodel.sdmx30.Metadataflow; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class MetadataflowWriterTest extends BaseJsonWriterTest { + + @InjectMocks + public MetadataflowWriter metadataflowWriter; + @InjectMocks + public DataflowWriter dataFlowWriter; + + @Test + void writeMetadataFlowToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Metadataflow metadataflow = MaintainableArtifactsTestUtils.buildMetadataFlow(); + + //when + metadataflowWriter.writeAndClose(createJsonGenerator(stream), metadataflow); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(METADATA_FLOW_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } + + @Test + void writeDataFlowToJson() throws IOException, URISyntaxException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Dataflow dataflow = MaintainableArtifactsTestUtils.buildDataFlow(); + AnnotationImpl annotation = (AnnotationImpl) dataflow.getAnnotations() + .get(0); + annotation.setUrl(new InternationalUri(new URI("http://some.com"))); + dataflow.getAnnotations() + .clear(); + dataflow.getAnnotations() + .add(annotation); + + //when + dataFlowWriter.writeAndClose(createJsonGenerator(stream), dataflow); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(DATA_FLOW_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/RepresentationMapWriterTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/RepresentationMapWriterTest.java new file mode 100644 index 0000000..42d0ec1 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/RepresentationMapWriterTest.java @@ -0,0 +1,38 @@ +package com.epam.jsdmx.json20.structure.writer; + +import static com.epam.jsdmx.json20.structure.TestUtils.REPRESENTATION_MAP_JSON; +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMap; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class RepresentationMapWriterTest extends BaseJsonWriterTest { + + @InjectMocks + public RepresentationMapWriter representationMapWriter; + + @Test + void writeRepresentationMapToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + RepresentationMap representationMap = MaintainableArtifactsTestUtils.buildRepresentationMap(); + + //when + representationMapWriter.writeAndClose(createJsonGenerator(stream), representationMap); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + String expected = IOUtils.resourceToString(REPRESENTATION_MAP_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } + +} diff --git a/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/StructureMapWriterTest.java b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/StructureMapWriterTest.java new file mode 100644 index 0000000..0a96222 --- /dev/null +++ b/sdmx-json20/src/test/java/com/epam/jsdmx/json20/structure/writer/StructureMapWriterTest.java @@ -0,0 +1,90 @@ +package com.epam.jsdmx.json20.structure.writer; + +import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.ComponentMap; +import com.epam.jsdmx.infomodel.sdmx30.ComponentMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.StructureMap; +import com.epam.jsdmx.infomodel.sdmx30.StructureMapImpl; +import com.epam.jsdmx.json20.structure.MaintainableArtifactsTestUtils; + +import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +class StructureMapWriterTest extends BaseJsonWriterTest { + + public static final String STRUCTURE_MAP_JSON = "/serialization.expected/structure-map.json"; + public static final String STRUCTURE_MAP_WITH_NULL_TARGET_SOURCE_JSON = "/serialization.expected/structure-map-with-null-target-source.json"; + public static final String STRUCTURE_MAP_WITH_NULL_MAP_JSON = "/serialization.expected/structure-map-with-null-map.json"; + @InjectMocks + public StructureMapWriter structureMapWriter; + + @Test + void writeStructureMapToJson() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + StructureMap structureMap = MaintainableArtifactsTestUtils.buildStructureMap(); + + //when + structureMapWriter.writeAndClose(createJsonGenerator(stream), structureMap); + String actual = stream.toString(StandardCharsets.UTF_8); + + //then + + String expected = IOUtils.resourceToString(STRUCTURE_MAP_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } + + @Test + void writeStructureMapToJsonWithNullTargetSource() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + StructureMapImpl structureMap = MaintainableArtifactsTestUtils.buildStructureMap(); + ComponentMapImpl componentMaRep = new ComponentMapImpl(); + MaintainableArtefactReference reference3 = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)"); + componentMaRep.setRepresentationMap(reference3); + List componentMaps = structureMap.getComponentMaps(); + List componentMapsAll = new ArrayList<>(componentMaps); + componentMapsAll.add(componentMaRep); + structureMap.setComponentMaps(componentMapsAll); + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + structureMapWriter.writeAndClose(jGenerator, structureMap); + String actual = stream.toString(StandardCharsets.UTF_8); + //then + String expected = IOUtils.resourceToString(STRUCTURE_MAP_WITH_NULL_TARGET_SOURCE_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } + + @Test + void writeStructureMapToJsonWithNullMap() throws IOException { + //given + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + StructureMapImpl structureMap = MaintainableArtifactsTestUtils.buildStructureMap(); + structureMap.setComponentMaps(null); + //when + JsonFactory jfactory = new JsonFactory(); + JsonGenerator jGenerator = jfactory.createGenerator(stream, JsonEncoding.UTF8); + structureMapWriter.writeAndClose(jGenerator, structureMap); + String actual = stream.toString(StandardCharsets.UTF_8); + //then + String expected = IOUtils.resourceToString(STRUCTURE_MAP_WITH_NULL_MAP_JSON, StandardCharsets.UTF_8); + + assertJsonEquals(expected, actual); + } +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/category-schema2.json b/sdmx-json20/src/test/resources/deserialization.expected/category-schema2.json new file mode 100644 index 0000000..34eb7fb --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/category-schema2.json @@ -0,0 +1,30 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "isPartial": true, + "categories": [] +} \ No newline at end of file diff --git a/sdmx-json20/src/test/resources/deserialization.expected/codelist_wild.json b/sdmx-json20/src/test/resources/deserialization.expected/codelist_wild.json new file mode 100644 index 0000000..b3f170d --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/codelist_wild.json @@ -0,0 +1,82 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "isPartial": true, + "codes": [ + { + "annotations": [], + "id": "CODE1", + "name": "code 1", + "names": { + "en": "code 1" + }, + "description": "code 1 desc", + "descriptions": { + "en": "code 1 desc" + }, + "parent": "CODE2" + }, + { + "annotations": [], + "id": "CODE2", + "name": "code 2", + "names": { + "en": "code 2" + }, + "description": "code 2 desc", + "descriptions": { + "en": "code 2 desc" + } + } + ], + "codelistExtensions": [ + { + "prefix": "PREF2", + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "inclusiveCodeSelection": { + "memberValues": [ + { + "value": "mem1", + "cascadeSelection": "true" + } + ] + } + }, + { + "prefix": "PREF2", + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "exclusiveCodeSelection": { + "memberValues": [ + { + "value": "mem2", + "cascadeSelection": "false" + } + ] + } + } + ] +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/concept-schema.json b/sdmx-json20/src/test/resources/deserialization.expected/concept-schema.json new file mode 100644 index 0000000..91d0931 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/concept-schema.json @@ -0,0 +1,59 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "concepts": [ + { + "annotations": [], + "id": "COUNTRY", + "name": "Country", + "names": { + "en": "Country" + }, + "coreRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + }, + { + "annotations": [], + "id": "COUNTRY2", + "name": "Country", + "names": { + "en": "Country" + }, + "coreRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)", + "enumerationFormat": { + "pattern": "RYtGKbgicZaHCBRQDSx" + } + } + } + ], + "isPartial": true +} \ No newline at end of file diff --git a/sdmx-json20/src/test/resources/deserialization.expected/data-flow.json b/sdmx-json20/src/test/resources/deserialization.expected/data-flow.json new file mode 100644 index 0000000..c2cede0 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/data-flow.json @@ -0,0 +1,34 @@ +{ + "agencyID": "IMF", + "id": "1", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + }, + "links": [ + { + "uri": "http://some.com" + } + ] + } + ], + "structure": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)" +} \ No newline at end of file diff --git a/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-attr.json b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-attr.json new file mode 100644 index 0000000..48a5d34 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-attr.json @@ -0,0 +1,87 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [ + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-1", + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-2", + "attributeRelationship": { + "dimensions": [ + "dim1", + "dim2" + ] + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-3", + "attributeRelationship": { + "none": {} + } + } + ], + "attributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "annotations": [], + "id": "DA1", + "isMandatory": false, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "group": "GroupKey" + }, + "measureRelationship": [ + "MO" + ], + "localRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + } + ] + }, + "dimensionList": {}, + "measureList": {} + } +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-attr_and_null.json b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-attr_and_null.json new file mode 100644 index 0000000..1f2ff9d --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-attr_and_null.json @@ -0,0 +1,87 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [ + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-1", + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-2", + "attributeRelationship": { + "dimensions": [ + "dim1", + "dim2" + ] + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-3", + "attributeRelationship": { + "none": {} + } + } + ], + "attributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "annotations": [], + "id": "DA1", + "isMandatory": false, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "group": "GroupKey" + }, + "measureRelationship": [ + "MO" + ], + "localRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + } + ] + }, + "dimensionList": null, + "measureList": null + } +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-attr_null.json b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-attr_null.json new file mode 100644 index 0000000..1993f20 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-attr_null.json @@ -0,0 +1,87 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": null, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "annotations": [], + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE" + ], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "annotations": [], + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod" + } + } + } + ] + }, + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "MES1", + "isMandatory": false, + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod", + "isMultiLingual": false + } + } + } + ] + } + } +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-components_empty.json b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-components_empty.json new file mode 100644 index 0000000..ac7e755 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-components_empty.json @@ -0,0 +1,34 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": {}, + "dimensionList": {}, + "measureList": {} + } +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-components_null.json b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-components_null.json new file mode 100644 index 0000000..a743726 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-components_null.json @@ -0,0 +1,34 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": null, + "dimensionList": null, + "measureList": null + } +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-dim.json b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-dim.json new file mode 100644 index 0000000..11b4385 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-dim.json @@ -0,0 +1,66 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": {}, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "annotations": [], + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE" + ], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "annotations": [], + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod" + } + } + } + ] + }, + "measureList": {} + } +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-dim_and_null.json b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-dim_and_null.json new file mode 100644 index 0000000..13a84d6 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-dim_and_null.json @@ -0,0 +1,66 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": null, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "annotations": [], + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE" + ], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "annotations": [], + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod" + } + } + } + ] + }, + "measureList": null + } +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-dim_null.json b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-dim_null.json new file mode 100644 index 0000000..f06555f --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-dim_null.json @@ -0,0 +1,108 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [ + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-1", + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-2", + "attributeRelationship": { + "dimensions": [ + "dim1", + "dim2" + ] + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-3", + "attributeRelationship": { + "none": {} + } + } + ], + "attributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "annotations": [], + "id": "DA1", + "isMandatory": false, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "group": "GroupKey" + }, + "measureRelationship": [ + "MO" + ], + "localRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + } + ] + }, + "dimensionList": null, + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "MES1", + "isMandatory": true, + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod", + "isMultiLingual": false + } + } + } + ] + } + } +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-full.json b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-full.json new file mode 100644 index 0000000..7a785f7 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-full.json @@ -0,0 +1,140 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [ + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-1", + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-2", + "attributeRelationship": { + "dimensions": [ + "dim1", + "dim2" + ] + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-3", + "attributeRelationship": { + "none": {} + } + } + ], + "attributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "annotations": [], + "id": "DA1", + "isMandatory": false, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "group": "GroupKey" + }, + "measureRelationship": [ + "MO" + ], + "localRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + } + ] + }, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "annotations": [], + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE" + ], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "annotations": [], + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod" + } + } + } + ] + }, + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "MES1", + "isMandatory": false, + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod", + "isMultiLingual": false + } + } + } + ] + } + } +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-meas.json b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-meas.json new file mode 100644 index 0000000..ceefb23 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-meas.json @@ -0,0 +1,55 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": {}, + "dimensionList": {}, + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "MES1", + "isMandatory": true, + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod", + "isMultiLingual": false + } + } + } + ] + } + } +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-meas_and_null.json b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-meas_and_null.json new file mode 100644 index 0000000..8e53541 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-meas_and_null.json @@ -0,0 +1,55 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": null, + "dimensionList": null, + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "MES1", + "isMandatory": true, + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod", + "isMultiLingual": false + } + } + } + ] + } + } +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-meas_null.json b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-meas_null.json new file mode 100644 index 0000000..52d86b5 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/data-structure-definition-meas_null.json @@ -0,0 +1,119 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [ + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-1", + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-2", + "attributeRelationship": { + "dimensions": [ + "dim1", + "dim2" + ] + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-3", + "attributeRelationship": { + "none": {} + } + } + ], + "attributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "annotations": [], + "id": "DA1", + "isMandatory": false, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "group": "GroupKey" + }, + "measureRelationship": [ + "MO" + ], + "localRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + } + ] + }, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "annotations": [], + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE" + ], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "annotations": [], + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod" + } + } + } + ] + }, + "measureList": null + } +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/hierarchy.json b/sdmx-json20/src/test/resources/deserialization.expected/hierarchy.json new file mode 100644 index 0000000..85d2817 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/hierarchy.json @@ -0,0 +1,74 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "hasFormalLevels": true, + "hierarchicalCodes": [ + { + "annotations": [ + { + "id": "id" + } + ], + "id": "id", + "validFrom": "2022-07-17T10:11:16.345Z", + "validTo": "2022-07-17T10:11:16.345Z", + "code": "urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1", + "level": "Lev1", + "hierarchicalCodes": [ + { + "annotations": [], + "id": "1", + "validFrom": "2022-07-17T10:11:16.345Z", + "validTo": "2022-07-17T10:11:16.345Z", + "code": "urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1" + } + ] + } + ], + "level": { + "annotations": [], + "id": "levId", + "name": "hierarchy name", + "names": { + "en": "hierarchy name" + }, + "description": "hierarchy desc", + "descriptions": { + "en": "hierarchy desc" + }, + "codingFormat": { + "interval": 1 + }, + "level": { + "annotations": [], + "id": "levUn", + "name": "underLevel", + "names": { + "en": "underLevel" + }, + "codingFormat": {} + } + } +} \ No newline at end of file diff --git a/sdmx-json20/src/test/resources/deserialization.expected/hierarchy2.json b/sdmx-json20/src/test/resources/deserialization.expected/hierarchy2.json new file mode 100644 index 0000000..5b04525 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/hierarchy2.json @@ -0,0 +1,58 @@ +{ + "annotations": [ + { + "id": "origin", + "title": null, + "type": null, + "value": "WORKSPACE", + "text": null + }, + { + "id": "parentUrn", + "title": null, + "type": null, + "value": null, + "text": "urn:sdmx:org.sdmx.infomodel.codelist.Hierarchy=OSB:A_HIERARCHY(1.0.0-draft)", + "texts": { + "en": "urn:sdmx:org.sdmx.infomodel.codelist.Hierarchy=OSB:A_HIERARCHY(1.0.0-draft)" + } + }, + { + "id": "lastUpdatedAt", + "title": null, + "type": null, + "value": "2023-11-27T17:25:04.733538Z", + "text": null + } + ], + "id": "A_HIERARCHY", + "name": "A Hierarchy", + "names": { + "en": "A Hierarchy" + }, + "description": null, + "descriptions": {}, + "version": "1.0.0", + "agencyID": "OSB", + "hasFormalLevels": false, + "hierarchicalCodes": [ + { + "annotations": [], + "id": "___KK", + "validFrom": null, + "validTo": null, + "code": "urn:sdmx:org.sdmx.infomodel.codelist.Code=OSB:A_CL_UNIT(1.0+.0).KK", + "level": "0", + "hierarchicalCodes": [ + { + "annotations": [], + "id": "___K", + "validFrom": null, + "validTo": null, + "code": "urn:sdmx:org.sdmx.infomodel.codelist.Code=OSB:A_CL_UNIT(1.0+.0).K", + "level": "0" + } + ] + } + ] +} \ No newline at end of file diff --git a/sdmx-json20/src/test/resources/deserialization.expected/json.json b/sdmx-json20/src/test/resources/deserialization.expected/json.json new file mode 100644 index 0000000..6382a1e --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/json.json @@ -0,0 +1,144 @@ +{ + "data": { + "categorisations": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "source": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Categorisation=IMF:ARTEFACT(1.2).CAT_SOURCE", + "target": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Category=IMF:ARTEFACT(1.2).CAT_TARGET" + } + ], + "structureMaps": [ + { + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "id": "FR1", + "annotations": [] + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "id": "FR2", + "annotations": [] + }, + { + "frequencyId": "CODE_3", + "datePattern": "2022-11", + "id": "FR3", + "annotations": [] + } + ], + "datePatternMaps": [ + { + "mappedComponents": [ + { + "source": "CompMapDPS", + "target": "CompMapDPT" + } + ], + "mappedFrequencies": [ + "FR1", + "FR2" + ], + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "DP1", + "locale": "EN", + "yearStart": {}, + "sourcePattern": "SOURCE" + } + ], + "fixedValueMaps": [ + { + "annotations": [], + "value": "value" + } + ], + "epochMaps": [ + { + "basePeriod": "2022-07-17T10:11:16.000000", + "mappedComponents": [ + { + "source": "CompMapEpochS", + "target": "CompMapEpochT" + } + ], + "mappedFrequencies": [ + "FR3" + ], + "epochPeriod": "Microsecond", + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "EPOCH1", + "yearStart": {} + } + ], + "componentMaps": [ + { + "source": [ + "CompMapRepS" + ], + "target": [ + "CompMapRepT" + ], + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)" + } + ], + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16.000000", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16.000000" + } + ] + } +} \ No newline at end of file diff --git a/sdmx-json20/src/test/resources/deserialization.expected/metadata-all-artefacts.json b/sdmx-json20/src/test/resources/deserialization.expected/metadata-all-artefacts.json new file mode 100644 index 0000000..c85ef8c --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/metadata-all-artefacts.json @@ -0,0 +1,67 @@ +{ + "data": { + "metadataSets": [ + { + "metadataflow": "urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=EPM:MetadataSet(1.8)", + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "reportingEnd": "2022", + "validFrom": "2022-07-17T10:11:16Z", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "targets": [ + "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataSet=EPM:MetadataSetTar(1.8)" + ], + "reportingBegin": "2022", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "publicationPeriod": "2022-03", + "publicationYear": "2022", + "action": "Append", + "attributes": [ + { + "id": "attr1", + "value": "someVal", + "attributes": [ + { + "id": "attr2", + "value": "someVal2" + } + ] + } + ], + "id": "1", + "validTo": "2022-07-17T10:11:16Z" + } + ] + }, + "meta": { + "schema": "https://raw.githubusercontent.com/sdmx-twg/sdmx-json/master/metadata-message/tools/schemas/2.0.0/sdmx-json-metadata-schema.json", + "id": "IDREF8124", + "test": false, + "prepared": "2021-11-02T09:47:41.000000", + "contentLanguages": [ + "en" + ], + "sender": { + "id": "unknown" + } + } +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/structure-maps-full.json b/sdmx-json20/src/test/resources/deserialization.expected/structure-maps-full.json new file mode 100644 index 0000000..fcca3b9 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/structure-maps-full.json @@ -0,0 +1,112 @@ +{ + "data": { + "structureMaps": [ + { + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "id": "FR1", + "annotations": [] + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "id": "FR2", + "annotations": [] + }, + { + "frequencyId": "CODE_3", + "datePattern": "2022-11", + "id": "FR3", + "annotations": [] + } + ], + "datePatternMaps": [ + { + "mappedComponents": [ + { + "source": "CompMapDPS", + "target": "CompMapDPT" + } + ], + "mappedFrequencies": [ + "FR1", + "FR2" + ], + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "DP1", + "locale": "EN", + "yearStart": {}, + "sourcePattern": "SOURCE" + } + ], + "fixedValueMaps": [ + { + "annotations": [], + "value": "value" + } + ], + "epochMaps": [ + { + "basePeriod": "2022-07-17T10:11:16.000000", + "mappedComponents": [ + { + "source": "CompMapEpochS", + "target": "CompMapEpochT" + } + ], + "mappedFrequencies": [ + "FR3" + ], + "epochPeriod": "Microsecond", + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "EPOCH1", + "yearStart": {} + } + ], + "componentMaps": [ + { + "source": [ + "CompMapRepS" + ], + "target": [ + "CompMapRepT" + ], + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)" + } + ], + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16.000000", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16.000000" + } + ] + } +} \ No newline at end of file diff --git a/sdmx-json20/src/test/resources/deserialization.expected/structure-maps-list-full.json b/sdmx-json20/src/test/resources/deserialization.expected/structure-maps-list-full.json new file mode 100644 index 0000000..2d77d36 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/structure-maps-list-full.json @@ -0,0 +1,187 @@ +{ + "data": { + "structureMaps": [ + { + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "id": "FR1", + "annotations": [] + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "id": "FR2", + "annotations": [] + }, + { + "frequencyId": "CODE_3", + "datePattern": "2022-11", + "id": "FR3", + "annotations": [] + } + ], + "datePatternMaps": [ + { + "mappedComponents": [ + { + "source": "CompMapDPS", + "target": "CompMapDPT" + } + ], + "mappedFrequencies": [ + "FR1", + "FR2" + ], + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "DP1", + "locale": "EN", + "yearStart": {}, + "sourcePattern": "SOURCE" + } + ], + "fixedValueMaps": [ + { + "annotations": [], + "value": "value" + } + ], + "epochMaps": [ + { + "basePeriod": "2022-07-17T10:11:16.000000", + "mappedComponents": [ + { + "source": "CompMapEpochS", + "target": "CompMapEpochT" + } + ], + "mappedFrequencies": [ + "FR3" + ], + "epochPeriod": "Microsecond", + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "EPOCH1", + "yearStart": {} + } + ], + "componentMaps": [ + { + "source": [ + "CompMapRepS" + ], + "target": [ + "CompMapRepT" + ], + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)" + } + ], + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16.000000", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16.000000" + }, + { + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "id": "FR1", + "annotations": [] + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "id": "FR2", + "annotations": [] + } + ], + "datePatternMaps": [ + { + "mappedComponents": [ + { + "source": "CompMapDPS", + "target": "CompMapDPT" + } + ], + "mappedFrequencies": [ + "FR1", + "FR2" + ], + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "DP1", + "locale": "EN", + "yearStart": {}, + "sourcePattern": "SOURCE" + } + ], + "componentMaps": [ + { + "source": [ + "CompMapRepS" + ], + "target": [ + "CompMapRepT" + ], + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=QUANTHUB:STRUC_ID2(1.2).REPRES" + } + ], + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "QUANTHUB", + "validFrom": "2022-07-17T10:11:16.000000", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "id": "STRUC_ID2", + "validTo": "2022-07-17T10:11:16.000000" + } + ] + } +} \ No newline at end of file diff --git a/sdmx-json20/src/test/resources/deserialization.expected/structures-all-artefacts.json b/sdmx-json20/src/test/resources/deserialization.expected/structures-all-artefacts.json new file mode 100644 index 0000000..6717afa --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/structures-all-artefacts.json @@ -0,0 +1,886 @@ +{ + "data": { + "categorisations": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "source": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Categorisation=IMF:ARTEFACT(1.2).CAT_SOURCE", + "target": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Category=IMF:ARTEFACT(1.2).CAT_TARGET" + } + ], + "structureMaps": [ + { + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "id": "FR1", + "annotations": [] + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "id": "FR2", + "annotations": [] + }, + { + "frequencyId": "CODE_3", + "datePattern": "2022-11", + "id": "FR3", + "annotations": [] + } + ], + "datePatternMaps": [ + { + "mappedComponents": [ + { + "source": "CompMapDPS", + "target": "CompMapDPT" + } + ], + "mappedFrequencies": [ + "FR1", + "FR2" + ], + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "DP1", + "locale": "EN", + "yearStart": {}, + "sourcePattern": "SOURCE" + } + ], + "fixedValueMaps": [ + { + "annotations": [], + "value": "value" + } + ], + "epochMaps": [ + { + "basePeriod": "2022-07-17T10:11:16.000000", + "mappedComponents": [ + { + "source": "CompMapEpochS", + "target": "CompMapEpochT" + } + ], + "mappedFrequencies": [ + "FR3" + ], + "epochPeriod": "Microsecond", + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "EPOCH1", + "yearStart": {} + } + ], + "componentMaps": [ + { + "source": [ + "CompMapRepS" + ], + "target": [ + "CompMapRepT" + ], + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)" + } + ], + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16.000000", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16.000000" + } + ], + "categorySchemes": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "isPartial": true, + "categories": [ + { + "annotations": [], + "id": "23423", + "name": "Category1", + "names": { + "en": "Category1" + }, + "description": "description", + "descriptions": { + "en": "description" + }, + "categories": [ + { + "annotations": [], + "id": "23422", + "name": "Category2", + "names": { + "en": "Category2" + }, + "description": "description category1", + "descriptions": { + "en": "description category1" + } + } + ] + } + ] + } + ], + "codelists": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "isPartial": true, + "codes": [ + { + "annotations": [], + "id": "CODE1", + "name": "code 1", + "names": { + "en": "code 1" + }, + "description": "code 1 desc", + "descriptions": { + "en": "code 1 desc" + }, + "parent": "CODE2" + }, + { + "annotations": [], + "id": "CODE2", + "name": "code 2", + "names": { + "en": "code 2" + }, + "description": "code 2 desc", + "descriptions": { + "en": "code 2 desc" + } + } + ], + "codelistExtensions": [ + { + "prefix": "PREF2", + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "inclusiveCodeSelection": { + "memberValues": [ + { + "value": "mem1", + "cascadeSelection": "true" + } + ] + } + }, + { + "prefix": "PREF2", + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "exclusiveCodeSelection": { + "memberValues": [ + { + "value": "mem2", + "cascadeSelection": "false" + } + ] + } + } + ] + } + ], + "conceptSchemes": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "concepts": [ + { + "annotations": [], + "id": "COUNTRY", + "name": "Country", + "names": { + "en": "Country" + }, + "coreRepresentation": {} + } + ] + } + ], + "dataStructures": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [ + { + "annotations": [], + "metadataAttributeReference": "12", + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "metadataAttributeReference": "1", + "attributeRelationship": { + "dimensions": [ + "dim1", + "dim2" + ] + } + }, + { + "annotations": [], + "metadataAttributeReference": "2", + "attributeRelationship": { + "none": {} + } + } + ], + "attributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "annotations": [], + "id": "DA1", + "isMandatory": true, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "none": {} + }, + "measureRelationship": [ + "MO" + ], + "localRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + } + ] + }, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "annotations": [], + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "annotations": [], + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": {} + } + ] + }, + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "MES1", + "isMandatory": true, + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod", + "isMultiLingual": false + } + } + } + ] + } + } + } + ], + "hierarchies": [ + { + "level": { + "names": { + "en": "hierarchy name" + }, + "name": "hierarchy name", + "annotations": [], + "description": "hierarchy desc", + "id": "levId", + "descriptions": { + "en": "hierarchy desc" + }, + "codingFormat": { + "interval": 1, + "isSequence": true, + "maxLength": 1, + "minLength": 1, + "maxValue": 1, + "minValue": 1, + "pattern": "a", + "startValue": 1, + "endValue": 1, + "dataType": "Alpha" + } + }, + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16.000000", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "hierarchicalCodes": [ + { + "code": "urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1", + "level": "Lev1", + "annotations": [], + "validFrom": "2022-07-17T10:11:16.345Z", + "validTo": "2022-07-17T10:11:16.345Z" + } + ], + "id": "ARTEFACT", + "hasFormalLevels": true, + "validTo": "2022-07-17T10:11:16.000000" + } + ], + "metadataflows": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=IMF:ARTEFACT(1.2)", + "type": "metadataflow", + "rel": "self" + } + ], + "structure": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=IMF:METADATA(1.0.0)" + } + ], + "metadataStructures": [ + { + "metadataStructureComponents": { + "metadataAttributeList": { + "annotations": [ + { + "id": "Annot-1", + "text": null, + "title": null, + "type": null, + "value": null + } + ], + "metadataAttributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataAttributeDescriptor=1:1(1.0).2", + "minOccurs": 10, + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=EPM:dim1(1.0)" + }, + "annotations": [], + "maxOccurs": 20, + "id": "1", + "isPresentational": true, + "metadataAttributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataAttributeDescriptor=1:1(1.0).2", + "minOccurs": 10, + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=EPM:dim1(1.0)" + }, + "annotations": [], + "maxOccurs": 20, + "id": "1", + "isPresentational": true + } + ] + } + ], + "id": "1" + } + }, + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "description": "Some artefact", + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "title": null, + "type": "type1", + "value": null + } + ], + "agencyID": "IMF", + "id": "ARTEFACT", + "validFrom": "2022-07-17T10:11:16.000000", + "version": "1.2", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000" + } + ], + "representationMaps": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "source": [ + { + "codelist": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:SOURCE(1.5.1)" + }, + { + "dataType": "DateTime" + } + ], + "target": [ + { + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_SOURCE(1.0)" + } + ], + "representationMappings": [ + { + "annotations": [], + "validTo": "2022-07-17T00:00:00.000Z", + "validFrom": "2022-07-17T00:00:00.000Z", + "sourceValues": [ + { + "value": "mappedValue", + "isRegEx": true, + "startIndex": 0, + "endIndex": 10 + } + ], + "targetValues": [ + "targetValue1", + "targetValue2" + ] + } + ] + } + ], + "dataflows": [ + { + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "structure": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)" + } + ], + "dataConstraints": [ + { + "annotations": [ + { + "id": "1", + "title": null, + "type": "type1", + "value": null, + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "role": "Allowed", + "constraintAttachment": { + "dataProvider": "urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP" + }, + "releaseCalendar": { + "tolerance": "Tolerance", + "offset": "Offset", + "periodicity": "Periodicity" + }, + "dataKeySets": [ + { + "isIncluded": true, + "keys": [ + { + "annotations": [], + "keyValues": [ + { + "id": "C1", + "include": true, + "removePrefix": true, + "value": "Value" + } + ], + "components": [ + { + "id": "MS", + "include": false, + "removePrefix": true, + "values": [ + { + "value": "MEM" + } + ] + }, + { + "id": "MS2", + "include": false, + "removePrefix": true, + "timeRange": { + "beforePeriod": { + "period": "2023", + "isInclusive": true + } + } + } + ], + "include": true, + "validFrom": "2022-07-17T10:11:16Z", + "validTo": "2022-07-17T10:11:16Z" + } + ] + } + ], + "cubeRegions": [ + { + "include": true, + "components": [ + { + "id": "some component id 1", + "include": true, + "removePrefix": true, + "values": [ + { + "value": "selectionValue1", + "lang": "en" + } + ] + }, + { + "id": "some component id 2", + "include": true, + "removePrefix": true, + "values": [ + { + "value": "selectionValue2", + "cascadeValues": "true", + "validFrom": "2020-04-12T12:00:00Z", + "validTo": "2020-05-12T12:00:00Z" + }, + { + "value": "selectionValue5" + } + ] + } + ], + "keyValues": [ + { + "id": "123", + "include": true, + "removePrefix": true, + "validFrom": "2020-04-12T12:00:00Z", + "validTo": "2022-04-12T12:00:00Z", + "timeRange": { + "beforePeriod": { + "period": "2020", + "isInclusive": false + }, + "afterPeriod": { + "period": "2021", + "isInclusive": false + } + } + } + ], + "annotations": [ + { + "id": "Annot", + "title": null, + "type": null, + "value": null, + "text": null + } + ] + } + ] + } + ] + }, + "meta": { + "schema": "https://raw.githubusercontent.com/sdmx-twg/sdmx-json/master/metadata-message/tools/schemas/2.0.0/sdmx-json-metadata-schema.json", + "id": "IDREF8124", + "test": false, + "prepared": "2021-11-02T09:47:41.000000", + "contentLanguages": [ + "en" + ], + "sender": { + "id": "unknown" + } + } +} diff --git a/sdmx-json20/src/test/resources/deserialization.expected/test.json b/sdmx-json20/src/test/resources/deserialization.expected/test.json new file mode 100644 index 0000000..135d5a7 --- /dev/null +++ b/sdmx-json20/src/test/resources/deserialization.expected/test.json @@ -0,0 +1,147 @@ +{ + "dataStructureComponents": { + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [], + "attributes": [ + { + "annotations": [], + "id": "COMMENT", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=QUANTHUB:ECOFIN_CONCEPTS(1.0).COMMENT", + "isMandatory": false, + "conceptRoles": [], + "attributeRelationship": { + "none": {} + } + }, + { + "annotations": [], + "id": "BASE_PER", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=SDMX:CROSS_DOMAIN_CONCEPTS(1.0).BASE_PER", + "isMandatory": false, + "conceptRoles": [], + "attributeRelationship": { + "dimensions": [ + "DATA_DOMAIN", + "REF_AREA", + "INDICATOR", + "COUNTERPART_AREA", + "FREQ" + ] + } + }, + { + "annotations": [], + "id": "UNIT_MULT", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=SDMX:CROSS_DOMAIN_CONCEPTS(1.0).UNIT_MULT", + "isMandatory": false, + "conceptRoles": [], + "attributeRelationship": { + "dimensions": [ + "DATA_DOMAIN", + "REF_AREA", + "INDICATOR", + "COUNTERPART_AREA", + "FREQ" + ] + } + }, + { + "annotations": [], + "id": "OBS_STATUS", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=SDMX:CROSS_DOMAIN_CONCEPTS(1.0).OBS_STATUS", + "isMandatory": false, + "conceptRoles": [], + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "id": "TIME_FORMAT", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=SDMX:CROSS_DOMAIN_CONCEPTS(1.0).TIME_FORMAT", + "isMandatory": false, + "conceptRoles": [], + "attributeRelationship": { + "dimensions": [ + "DATA_DOMAIN", + "REF_AREA", + "INDICATOR", + "COUNTERPART_AREA", + "FREQ" + ] + } + } + ] + }, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "annotations": [], + "id": "DATA_DOMAIN", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=QUANTHUB:ECOFIN_CONCEPTS(1.0).DATA_DOMAIN", + "position": 0, + "type": "Dimension", + "conceptRoles": [] + }, + { + "annotations": [], + "id": "REF_AREA", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=QUANTHUB:ECOFIN_CONCEPTS(2.0.0-draft).REF_AREA", + "position": 1, + "type": "Dimension", + "conceptRoles": [] + }, + { + "annotations": [], + "id": "INDICATOR", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=QUANTHUB:ECOFIN_CONCEPTS(1.0).INDICATOR", + "position": 2, + "type": "Dimension", + "conceptRoles": [] + }, + { + "annotations": [], + "id": "COUNTERPART_AREA", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=QUANTHUB:ECOFIN_CONCEPTS(1.0).COUNTERPART_AREA", + "position": 3, + "type": "Dimension", + "conceptRoles": [] + }, + { + "annotations": [], + "id": "FREQ", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=SDMX:CROSS_DOMAIN_CONCEPTS(1.0).FREQ", + "position": 4, + "type": "Dimension", + "conceptRoles": [] + } + ], + "timeDimensions": [ + { + "annotations": [], + "id": "TIME_PERIOD", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=SDMX:CROSS_DOMAIN_CONCEPTS(1.0).TIME_PERIOD", + "position": 5, + "type": "TimeDimension" + } + ] + }, + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "OBS_VALUE", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=SDMX:CROSS_DOMAIN_CONCEPTS(1.0).OBS_VALUE", + "isMandatory": false, + "conceptRoles": [] + } + ] + } + } +} \ No newline at end of file diff --git a/sdmx-json20/src/test/resources/serialization.expected/agency-scheme.json b/sdmx-json20/src/test/resources/serialization.expected/agency-scheme.json new file mode 100644 index 0000000..e1db11b --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/agency-scheme.json @@ -0,0 +1,141 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "AGENCIES", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.0", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "SDMX", + "isPartial": false, + "agencies": [ + { + "annotations": [ + { + "id": "Annot" + } + ], + "id": "AG-1", + "name": "Agency", + "names": { + "en": "Agency" + }, + "description": "Agency", + "descriptions": { + "en": "Agency" + }, + "contacts": [ + { + "name": "AG_1", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + }, + { + "name": "AG_2", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax2" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + } + ] + }, + { + "annotations": [], + "id": "AG-2", + "name": "Agency", + "names": { + "en": "Agency" + }, + "description": "Agency", + "descriptions": { + "en": "Agency" + }, + "contacts": [ + { + "name": "AG_1", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + }, + { + "name": "AG_2", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax2" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + } + ] + } + ] +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/attribute-list.json b/sdmx-json20/src/test/resources/serialization.expected/attribute-list.json new file mode 100644 index 0000000..57e3450 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/attribute-list.json @@ -0,0 +1,55 @@ +{ + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [ + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-1", + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-2", + "attributeRelationship": { + "dimensions": [ + "dim1", + "dim2" + ] + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-3", + "attributeRelationship": { + "none": {} + } + } + ], + "attributes": [ + { + "annotations": [], + "id": "DA1", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "localRepresentation": { + "format": { + "dataType": "AlphaNumeric" + } + }, + "isMandatory": false, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "group": "GroupKey" + }, + "measureRelationship": [ + "MO" + ] + } + ] + } +} \ No newline at end of file diff --git a/sdmx-json20/src/test/resources/serialization.expected/attribute-list_empty.json b/sdmx-json20/src/test/resources/serialization.expected/attribute-list_empty.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/attribute-list_empty.json @@ -0,0 +1 @@ +{} diff --git a/sdmx-json20/src/test/resources/serialization.expected/categorisation.json b/sdmx-json20/src/test/resources/serialization.expected/categorisation.json new file mode 100644 index 0000000..cbd6079 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/categorisation.json @@ -0,0 +1,28 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "source": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Categorisation=IMF:ARTEFACT(1.2).CAT_SOURCE", + "target": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Category=IMF:ARTEFACT(1.2).CAT_TARGET" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/category-schema.json b/sdmx-json20/src/test/resources/serialization.expected/category-schema.json new file mode 100644 index 0000000..36c7f5a --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/category-schema.json @@ -0,0 +1,86 @@ +{ + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "type": "type1" + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16Z", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "isPartial": true, + "id": "ARTEFACT", + "categories": [ + { + "names": { + "en": "Category1" + }, + "name": "Category1", + "annotations": [ + { + "id": "Annot" + } + ], + "description": "description category 1", + "id": "Category-1", + "categories": [ + { + "names": { + "en": "Category2" + }, + "name": "Category2", + "annotations": [ + { + "id": "Annot" + }, + { + "id": "Annot2" + } + ], + "description": "description category2", + "id": "Category-2", + "descriptions": { + "en": "description category2" + } + }, + { + "names": { + "en": "Category3" + }, + "name": "Category3", + "annotations": [], + "description": "description category3", + "id": "Category-3", + "descriptions": { + "en": "description category3" + } + } + ], + "descriptions": { + "en": "description category 1" + } + }, + { + "names": { + "en": "Category4" + }, + "name": "Category4", + "annotations": [], + "id": "Category-4" + } + ], + "validTo": "2022-07-17T10:11:16Z" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/category-scheme-map.json b/sdmx-json20/src/test/resources/serialization.expected/category-scheme-map.json new file mode 100644 index 0000000..bc76be9 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/category-scheme-map.json @@ -0,0 +1,52 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "itemMaps": [ + { + "annotations": [ + { + "id": "Ann" + } + ], + "sourceValue": "S-1", + "targetValue": "IM-1", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + }, + { + "annotations": [ + { + "id": "Ann" + } + ], + "sourceValue": "S-2", + "targetValue": "IM-2", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + } + ], + "source": "urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:CatScheme(1.0)", + "target": "urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:CatScheme(1.1)" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/codelist.json b/sdmx-json20/src/test/resources/serialization.expected/codelist.json new file mode 100644 index 0000000..619445a --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/codelist.json @@ -0,0 +1,80 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "isPartial": true, + "codes": [ + { + "annotations": [], + "id": "CODE1", + "name": "code 1", + "names": { + "en": "code 1" + }, + "description": "code 1 desc", + "descriptions": { + "en": "code 1 desc" + }, + "parent": "CODE2" + }, + { + "annotations": [], + "id": "CODE2", + "name": "code 2", + "names": { + "en": "code 2" + }, + "description": "code 2 desc", + "descriptions": { + "en": "code 2 desc" + } + } + ], + "codelistExtensions": [ + { + "prefix": "PREF2", + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "inclusiveCodeSelection": { + "memberValues": [ + { + "value": "mem1", + "cascadeValues": "true" + } + ] + } + }, + { + "prefix": "PREF2", + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "exclusiveCodeSelection": { + "memberValues": [ + { + "value": "mem2", + "cascadeValues": "false" + } + ] + } + } + ] +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/concept-scheme-enumerated-concept.json b/sdmx-json20/src/test/resources/serialization.expected/concept-scheme-enumerated-concept.json new file mode 100644 index 0000000..804d5bf --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/concept-scheme-enumerated-concept.json @@ -0,0 +1,92 @@ +{ + "annotations": [ + { + "id": "origin", + "value": "WORKSPACE" + }, + { + "id": "parentUrn", + "text": "urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=OSB:A_CS_DATA(1.0.0-draft)", + "texts": { + "en": "urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=OSB:A_CS_DATA(1.0.0-draft)" + } + }, + { + "id": "lastUpdatedAt", + "value": "2023-11-20T21:42:24.123992Z" + } + ], + "id": "A_CS_DATA", + "name": "A CS Data", + "names": { + "en": "A CS Data" + }, + "descriptions": {}, + "version": "1.0.0", + "agencyID": "OSB", + "concepts": [ + { + "annotations": [], + "id": "INDICATOR", + "name": "Indicator", + "names": { + "en": "Indicator" + }, + "coreRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=OSB:A_CL_INDICATOR(1.0+.0)" + } + }, + { + "annotations": [], + "id": "FREQ", + "name": "Frequency", + "names": { + "en": "Frequency" + }, + "coreRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=OSB:A_CL_FREQ_EXTENDED(1.0+.0)" + } + }, + { + "annotations": [], + "id": "OBS_VALUE", + "name": "Observation Value", + "names": { + "en": "Observation Value" + }, + "coreRepresentation": { + "format": { + "dataType": "Decimal" + } + } + }, + { + "annotations": [], + "id": "COMMENT", + "name": "Comment", + "names": { + "en": "Comment" + }, + "coreRepresentation": { + "format": { + "dataType": "String", + "isMultiLingual": true + } + } + }, + { + "annotations": [], + "id": "TIME_PERIOD", + "name": "Time Period", + "names": { + "en": "Time Period" + }, + "coreRepresentation": { + "format": { + "dataType": "ObservationalTimePeriod" + } + } + } + ], + "isPartial": false +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/concept-scheme-map.json b/sdmx-json20/src/test/resources/serialization.expected/concept-scheme-map.json new file mode 100644 index 0000000..8198171 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/concept-scheme-map.json @@ -0,0 +1,52 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "itemMaps": [ + { + "annotations": [ + { + "id": "Ann" + } + ], + "sourceValue": "S-1", + "targetValue": "IM-1", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + }, + { + "annotations": [ + { + "id": "Ann" + } + ], + "sourceValue": "S-2", + "targetValue": "IM-2", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + } + ], + "source": "urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ConScheme(1.0)", + "target": "urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ConScheme(1.1)" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/concept-scheme.json b/sdmx-json20/src/test/resources/serialization.expected/concept-scheme.json new file mode 100644 index 0000000..88ce4f7 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/concept-scheme.json @@ -0,0 +1,60 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "concepts": [ + { + "annotations": [], + "id": "COUNTRY", + "name": "Country", + "names": { + "en": "Country" + }, + "coreRepresentation": { + "format": { + "dataType": "Alpha", + "sentinelValues": [ + { + "value": "val", + "name": "sent", + "names": { + "en": "sent" + }, + "description": "sentinel descr", + "descriptions": { + "en": "sentinel descr" + } + } + ] + } + }, + "isoConceptReference": { + "conceptSchemeID": "Schema", + "conceptID": "Conn", + "conceptAgency": "QHB" + } + } + ], + "isPartial": true +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/data-constraint-empty.json b/sdmx-json20/src/test/resources/serialization.expected/data-constraint-empty.json new file mode 100644 index 0000000..db55c40 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/data-constraint-empty.json @@ -0,0 +1,31 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "role": "Allowed", + "constraintAttachment": { + "dataProvider": "urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP" + }, + "cubeRegions": [] +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/data-constraint.json b/sdmx-json20/src/test/resources/serialization.expected/data-constraint.json new file mode 100644 index 0000000..5965521 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/data-constraint.json @@ -0,0 +1,137 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "role": "Allowed", + "constraintAttachment": { + "dataProvider": "urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP" + }, + "releaseCalendar": { + "tolerance": "Tolerance", + "offset": "Offset", + "periodicity": "Periodicity" + }, + "dataKeySets": [ + { + "isIncluded": true, + "keys": [ + { + "annotations": [], + "keyValues": [ + { + "id": "C1", + "include": true, + "removePrefix": true, + "value": "Value" + } + ], + "components": [ + { + "id": "MS", + "include": false, + "removePrefix": true, + "values": [ + { + "value": "MEM" + } + ] + }, + { + "id": "MS2", + "include": false, + "removePrefix": true, + "timeRange": { + "beforePeriod": { + "period": "2023", + "isInclusive": true + } + } + } + ], + "include": true, + "validFrom": "2022-07-17T10:11:16Z", + "validTo": "2022-07-17T10:11:16Z" + } + ] + } + ], + "cubeRegions": [ + { + "include": true, + "components": [ + { + "id": "some component id 1", + "include": true, + "removePrefix": true, + "values": [ + { + "value": "selectionValue1", + "lang": "en" + } + ] + }, + { + "id": "some component id 2", + "include": true, + "removePrefix": true, + "values": [ + { + "value": "selectionValue2", + "cascadeValues": "true", + "validFrom": "2020-04-12T12:00:00Z", + "validTo": "2020-05-12T12:00:00Z" + }, + { + "value": "selectionValue5" + } + ] + } + ], + "keyValues": [ + { + "id": "123", + "include": true, + "removePrefix": true, + "validFrom": "2020-04-12T12:00:00Z", + "validTo": "2022-04-12T12:00:00Z", + "timeRange": { + "beforePeriod": { + "period": "2020", + "isInclusive": false + }, + "afterPeriod": { + "period": "2021", + "isInclusive": false + } + } + } + ], + "annotations": [ + { + "id": "Annot" + } + ] + } + ] +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/data-consumer-scheme.json b/sdmx-json20/src/test/resources/serialization.expected/data-consumer-scheme.json new file mode 100644 index 0000000..94c341c --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/data-consumer-scheme.json @@ -0,0 +1,83 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "DATA_CONSUMERS", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.0", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "isPartial": false, + "dataConsumers": [ + { + "annotations": [], + "id": "DC", + "name": "Data Consumer", + "names": { + "en": "Data Consumer" + }, + "description": "Data Consumer description", + "descriptions": { + "en": "Data Consumer description" + }, + "contacts": [ + { + "name": "AG_1", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + }, + { + "name": "AG_2", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax2" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + } + ] + } + ] +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/data-flow.json b/sdmx-json20/src/test/resources/serialization.expected/data-flow.json new file mode 100644 index 0000000..e58db60 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/data-flow.json @@ -0,0 +1,32 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + }, + "links": [ + { + "uri": "http://some.com" + } + ] + } + ], + "structure": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/data-provider-scheme.json b/sdmx-json20/src/test/resources/serialization.expected/data-provider-scheme.json new file mode 100644 index 0000000..91e4e4d --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/data-provider-scheme.json @@ -0,0 +1,84 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "DATA_PROVIDERS", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.0", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "isPartial": true, + "dataProviders": [ + { + "annotations": [ + { + "id": "Ann", + "value": "Val" + } + ], + "id": "Prov", + "name": "D_P", + "names": { + "en": "D_P" + }, + "contacts": [ + { + "name": "AG_1", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + }, + { + "name": "AG_2", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax2" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + } + ] + } + ] +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/data-structure-definition-order.json b/sdmx-json20/src/test/resources/serialization.expected/data-structure-definition-order.json new file mode 100644 index 0000000..3f6dc58 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/data-structure-definition-order.json @@ -0,0 +1,138 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16.000000", + "validFrom": "2022-07-17T10:11:16.000000", + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "dataStructureComponents": { + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "MES1", + "isMandatory": false, + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod", + "isMultiLingual": false + } + } + } + ] + }, + "attributeList": { + "annotations": [], + "id": "AttributeDescriptor", + "metadataAttributeUsages": [ + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-1", + "attributeRelationship": { + "observation": {} + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-2", + "attributeRelationship": { + "dimensions": [ + "dim1", + "dim2" + ] + } + }, + { + "annotations": [], + "metadataAttributeReference": "REFERENCE-3", + "attributeRelationship": { + "none": {} + } + } + ], + "attributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE", + "annotations": [], + "id": "DA1", + "isMandatory": false, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ], + "attributeRelationship": { + "group": "GroupKey" + }, + "measureRelationship": [ + "MO" + ], + "localRepresentation": { + "format": { + "dataType": "AlphaNumeric", + "isMultiLingual": false + } + } + } + ] + }, + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "annotations": [], + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE" + ], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "annotations": [], + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE", + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod" + } + } + } + ] + } + } +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/data-structure-definition.json b/sdmx-json20/src/test/resources/serialization.expected/data-structure-definition.json new file mode 100644 index 0000000..114a8bb --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/data-structure-definition.json @@ -0,0 +1,27 @@ +{ + "agencyID": "IMF", + "id": "ARTEFACT", + "version": "1.2", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "metadata": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/dimension-list.json b/sdmx-json20/src/test/resources/serialization.expected/dimension-list.json new file mode 100644 index 0000000..ee6029a --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/dimension-list.json @@ -0,0 +1,30 @@ +{ + "dimensionList": { + "annotations": [], + "id": "DimensionDescriptor", + "dimensions": [ + { + "position": 1, + "id": "DIM1", + "annotations": [], + "type": "Dimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE", + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE" + ], + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + } + } + ], + "timeDimensions": [ + { + "position": 2, + "id": "TIME_PERIOD", + "annotations": [], + "type": "TimeDimension", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE" + } + ] + } +} \ No newline at end of file diff --git a/sdmx-json20/src/test/resources/serialization.expected/dimension-list_empty.json b/sdmx-json20/src/test/resources/serialization.expected/dimension-list_empty.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/dimension-list_empty.json @@ -0,0 +1 @@ +{} diff --git a/sdmx-json20/src/test/resources/serialization.expected/empty-structure.json b/sdmx-json20/src/test/resources/serialization.expected/empty-structure.json new file mode 100644 index 0000000..bf9ef71 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/empty-structure.json @@ -0,0 +1,15 @@ +{ + "data": {}, + "meta": { + "schema": "https://raw.githubusercontent.com/sdmx-twg/sdmx-json/master/metadata-message/tools/schemas/2.0.0/sdmx-json-metadata-schema.json", + "id": "IDREF7553", + "test": false, + "prepared": "2022-04-03T15:35:01Z", + "contentLanguages": [ + "en" + ], + "sender": { + "id": "unknown" + } + } +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/expected-flat-json-streamer-response.json b/sdmx-json20/src/test/resources/serialization.expected/expected-flat-json-streamer-response.json new file mode 100644 index 0000000..a7e7435 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/expected-flat-json-streamer-response.json @@ -0,0 +1,110 @@ +{ + "meta": {}, + "data": { + "dataSets": [ + { + "structure": 0, + "action": "Information", + "observations": { + "0:0": [ + "obsValue2" + ], + "0:1": [ + "obsValue5" + ], + "1:1": [ + "obsValue6" + ] + } + } + ], + "structures": [ + { + "dataSets": [ + 0 + ], + "links": [ + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=QH:DF(4.20)", + "title": "Dataflow" + }, + { + "urn": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QH:DSD(4.20)", + "title": "DataStructureDefinition" + } + ], + "dimensions": { + "series": [ + { + "id": "dim1", + "keyPosition": 0, + "roles": [], + "values": [ + { + "value": "dim1-val1" + }, + { + "value": "dim1-val2" + } + ] + }, + { + "id": "dim2", + "keyPosition": 1, + "roles": [ + "role" + ], + "values": [ + { + "value": "dim2-val1" + }, + { + "value": "dim2-val2" + } + ] + } + ] + }, + "measures": { + "observation": [ + { + "id": "OBS_VALUE", + "roles": [] + } + ] + }, + "attributes": { + "dataSet": [ + { + "id": "dataset", + "roles": [], + "isMandatory": false, + "relationship": { + "dataflow": {} + } + } + ], + "observation": [ + { + "id": "observation1", + "roles": [], + "isMandatory": false, + "relationship": { + "observation": {} + } + }, + { + "id": "observation2", + "roles": [], + "isMandatory": false, + "relationship": { + "observation": {} + } + } + ] + }, + "annotations": [] + } + ] + } +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/geocodelist.json b/sdmx-json20/src/test/resources/serialization.expected/geocodelist.json new file mode 100644 index 0000000..f98b47d --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/geocodelist.json @@ -0,0 +1,83 @@ +{ + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "type": "type1" + } + ], + "description": "Some artefact", + "geoFeatureSetCodes": [ + { + "parent": "CODE2", + "names": { + "en": "code 1" + }, + "name": "code 1", + "annotations": [], + "description": "code 1 desc", + "id": "CODE1", + "descriptions": { + "en": "code 1 desc" + }, + "value": "Value1" + }, + { + "names": { + "en": "code 2" + }, + "name": "code 2", + "annotations": [], + "description": "code 2 desc", + "id": "CODE2", + "descriptions": { + "en": "code 2 desc" + }, + "value": "Value2" + } + ], + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16Z", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "codelistExtensions": [ + { + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "prefix": "PREF2", + "inclusiveCodeSelection": { + "memberValues": [ + { + "cascadeValues": "true", + "value": "mem1" + } + ] + } + }, + { + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "prefix": "PREF2", + "exclusiveCodeSelection": { + "memberValues": [ + { + "cascadeValues": "false", + "value": "mem2" + } + ] + } + } + ], + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "geoType": "GeographicCodelist", + "name": "Maintanable artefact", + "isPartial": true, + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16Z" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/geogridcodelist.json b/sdmx-json20/src/test/resources/serialization.expected/geogridcodelist.json new file mode 100644 index 0000000..99d8860 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/geogridcodelist.json @@ -0,0 +1,84 @@ +{ + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "type": "type1" + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16Z", + "geoGridCodes": [ + { + "parent": "CODE2", + "names": { + "en": "code 1" + }, + "geoCell": "Value1", + "name": "code 1", + "annotations": [], + "description": "code 1 desc", + "id": "CODE1", + "descriptions": { + "en": "code 1 desc" + } + }, + { + "names": { + "en": "code 2" + }, + "geoCell": "Value2", + "name": "code 2", + "annotations": [], + "description": "code 2 desc", + "id": "CODE2", + "descriptions": { + "en": "code 2 desc" + } + } + ], + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "codelistExtensions": [ + { + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "prefix": "PREF2", + "inclusiveCodeSelection": { + "memberValues": [ + { + "cascadeValues": "true", + "value": "mem1" + } + ] + } + }, + { + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)", + "prefix": "PREF2", + "exclusiveCodeSelection": { + "memberValues": [ + { + "cascadeValues": "false", + "value": "mem2" + } + ] + } + } + ], + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "geoType": "GeoGridCodelist", + "name": "Maintanable artefact", + "isPartial": true, + "id": "ARTEFACT", + "gridDefinition": "DEFINITION", + "validTo": "2022-07-17T10:11:16Z" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/group-dimension-list.json b/sdmx-json20/src/test/resources/serialization.expected/group-dimension-list.json new file mode 100644 index 0000000..179a4cf --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/group-dimension-list.json @@ -0,0 +1,29 @@ +{ + "groups": [ + { + "annotations": [ + { + "id": "id1", + "value": "val" + }, + { + "id": "id2", + "value": "val" + } + ], + "id": "GroupDimensionDescriptor1", + "groupDimensions": [ + "dim1", + "dim12" + ] + }, + { + "annotations": [], + "id": "GroupDimensionDescriptor2", + "groupDimensions": [ + "dim21", + "dim22" + ] + } + ] +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/hierarchy-association.json b/sdmx-json20/src/test/resources/serialization.expected/hierarchy-association.json new file mode 100644 index 0000000..c957c18 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/hierarchy-association.json @@ -0,0 +1,29 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "contextObject": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)", + "linkedHierarchy": "urn:sdmx:org.sdmx.infomodel.codelist.Hierarchy=IMF:ARTEFACT(1.2)", + "linkedObject": "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.3)" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/hierarchy.json b/sdmx-json20/src/test/resources/serialization.expected/hierarchy.json new file mode 100644 index 0000000..5058159 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/hierarchy.json @@ -0,0 +1,64 @@ +{ + "level": { + "names": { + "en": "hierarchy name" + }, + "name": "hierarchy name", + "annotations": [], + "description": "hierarchy desc", + "id": "levId", + "descriptions": { + "en": "hierarchy desc" + }, + "codingFormat": { + "interval": 1 + } + }, + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "type": "type1" + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16Z", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "hierarchicalCodes": [ + { + "code": "urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1", + "level": "Lev1", + "annotations": [ + { + "id": "id" + } + ], + "id": "id", + "validFrom": "2022-07-17T10:11:16.345Z", + "validTo": "2022-07-17T10:11:16.345Z" + }, + { + "code": "urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL2", + "level": "Lev2", + "annotations": [], + "id": "hi-2", + "validFrom": "2022-07-17T10:11:16.345Z", + "validTo": "2022-07-17T10:11:16.345Z" + } + ], + "id": "ARTEFACT", + "hasFormalLevels": true, + "validTo": "2022-07-17T10:11:16Z" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/measure-list.json b/sdmx-json20/src/test/resources/serialization.expected/measure-list.json new file mode 100644 index 0000000..0f9c749 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/measure-list.json @@ -0,0 +1,24 @@ +{ + "measureList": { + "annotations": [], + "id": "MeasureDescriptor", + "measures": [ + { + "annotations": [], + "id": "MES1", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE", + "localRepresentation": { + "format": { + "dataType": "BasicTimePeriod", + "isMultiLingual": false + } + }, + "isMandatory": false, + "conceptRoles": [ + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE", + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE" + ] + } + ] + } +} \ No newline at end of file diff --git a/sdmx-json20/src/test/resources/serialization.expected/measure-list_empty.json b/sdmx-json20/src/test/resources/serialization.expected/measure-list_empty.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/measure-list_empty.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/sdmx-json20/src/test/resources/serialization.expected/metadata-constraint.json b/sdmx-json20/src/test/resources/serialization.expected/metadata-constraint.json new file mode 100644 index 0000000..3dfc132 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/metadata-constraint.json @@ -0,0 +1,68 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "role": "Allowed", + "metadataTargetRegions": [ + { + "include": true, + "validFrom": "2022-07-17T10:11:16Z", + "validTo": "2022-07-17T10:11:16Z", + "components": [ + { + "include": false, + "id": "MS", + "removePrefix": true, + "values": [ + { + "value": "MEM", + "cascadeValues": "excluderoot", + "validFrom": "2022-07-17T10:11:16Z", + "validTo": "2022-09-17T10:11:16Z" + } + ] + }, + { + "include": false, + "id": "MS2", + "removePrefix": true, + "timeRange": { + "beforePeriod": { + "period": "2023", + "isInclusive": true + } + } + } + ] + } + ], + "releaseCalendar": { + "tolerance": "Tolerance", + "offset": "Offset", + "periodicity": "Periodicity" + }, + "constraintAttachment": { + "metadataProvider": "urn:sdmx:org.sdmx.infomodel.base.MetadataProvider=IMF:METADATA_PROVIDERS(1.0).PR" + } +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/metadata-flow.json b/sdmx-json20/src/test/resources/serialization.expected/metadata-flow.json new file mode 100644 index 0000000..3bc9e73 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/metadata-flow.json @@ -0,0 +1,31 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "structure": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=IMF:METADATA(1.0.0)", + "targets": [ + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)", + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.3)" + ] +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/metadata-provider-scheme.json b/sdmx-json20/src/test/resources/serialization.expected/metadata-provider-scheme.json new file mode 100644 index 0000000..2275f30 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/metadata-provider-scheme.json @@ -0,0 +1,84 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "METADATA_PROVIDERS", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.0", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "isPartial": true, + "metadataProviders": [ + { + "annotations": [ + { + "id": "Ann", + "value": "Val" + } + ], + "id": "Prov", + "name": "MD_P", + "names": { + "en": "MD_P" + }, + "contacts": [ + { + "name": "AG_1", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + }, + { + "name": "AG_2", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax2" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + } + ] + } + ] +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/metadata-provision-agreement.json b/sdmx-json20/src/test/resources/serialization.expected/metadata-provision-agreement.json new file mode 100644 index 0000000..c13adaf --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/metadata-provision-agreement.json @@ -0,0 +1,28 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "metadataProvider": "urn:sdmx:org.sdmx.infomodel.base.MetadataProvider=IMF:METADATA_PROVIDERS(1.0).PR", + "metadataflow": "urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=IMF:ARTEFACT(1.2)" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/metadata-structure-definition-multi-attributes.json b/sdmx-json20/src/test/resources/serialization.expected/metadata-structure-definition-multi-attributes.json new file mode 100644 index 0000000..b82e494 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/metadata-structure-definition-multi-attributes.json @@ -0,0 +1,58 @@ +{ + "annotations": [ + { + "id": "origin", + "value": "WORKSPACE" + }, + { + "id": "parentUrn", + "text": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=OSB:A_METADATA_STRUCTURE_DEFINITION(1.0.0-draft)", + "texts": { + "en": "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=OSB:A_METADATA_STRUCTURE_DEFINITION(1.0.0-draft)" + } + }, + { + "id": "lastUpdatedAt", + "value": "2023-11-22T09:06:37.267016Z" + } + ], + "id": "A_METADATA_STRUCTURE_DEFINITION", + "name": "A Metadata Structure Definition", + "names": { + "en": "A Metadata Structure Definition" + }, + "descriptions": {}, + "version": "1.0.0", + "agencyID": "OSB", + "metadataStructureComponents": { + "metadataAttributeList": { + "annotations": [], + "metadataAttributes": [ + { + "annotations": [], + "id": "META_UNIT", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=OSB:A_CS_META(1.0+.0).META_UNIT", + "maxOccurs": 1, + "minOccurs": 1, + "isPresentational": false + }, + { + "annotations": [], + "id": "META_COMMENT", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=OSB:A_CS_META(1.0+.0).META_COMMENT", + "maxOccurs": 1, + "minOccurs": 0, + "isPresentational": false + }, + { + "annotations": [], + "id": "META_AUTHORS", + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=OSB:A_CS_META(1.0+.0).META_AUTHORS", + "maxOccurs": 10, + "minOccurs": 0, + "isPresentational": false + } + ] + } + } +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/metadata-structure-definition.json b/sdmx-json20/src/test/resources/serialization.expected/metadata-structure-definition.json new file mode 100644 index 0000000..afea513 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/metadata-structure-definition.json @@ -0,0 +1,62 @@ +{ + "metadataStructureComponents": { + "metadataAttributeList": { + "annotations": [ + { + "id": "Annot-1" + } + ], + "metadataAttributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DIM", + "minOccurs": 10, + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + }, + "annotations": [], + "maxOccurs": 20, + "metadataAttributes": [ + { + "conceptIdentity": "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DIM", + "minOccurs": 10, + "localRepresentation": { + "enumeration": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)" + }, + "annotations": [], + "maxOccurs": 20, + "id": "meta-2", + "isPresentational": true + } + ], + "id": "meta-1", + "isPresentational": true + } + ], + "id": "MetadataAttributeDescriptor" + } + }, + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "type": "type1" + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "id": "ARTEFACT", + "validFrom": "2022-07-17T10:11:16Z", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/metadata.json b/sdmx-json20/src/test/resources/serialization.expected/metadata.json new file mode 100644 index 0000000..e1cdf56 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/metadata.json @@ -0,0 +1,66 @@ +{ + "data": { + "metadataSets": [ + { + "metadataflow": "urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=EPM:MetadataSet(1.8)", + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "type": "type1" + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "reportingEnd": "2022", + "validFrom": "2022-07-17T10:11:16Z", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "targets": [ + "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataSet=EPM:MetadataSetTar(1.8)" + ], + "reportingBegin": "2022", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "publicationPeriod": "2022-03", + "publicationYear": "2022", + "action": "Append", + "attributes": [ + { + "id": "attr1", + "value": "someVal", + "attributes": [ + { + "attributes": [], + "id": "attr2", + "value": "someVal2" + } + ] + } + ], + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16Z" + } + ] + }, + "meta": { + "schema": "https://raw.githubusercontent.com/sdmx-twg/sdmx-json/master/metadata-message/tools/schemas/2.0.0/sdmx-json-metadata-schema.json", + "id": "IDREF8124", + "test": false, + "prepared": "2021-11-02T09:47:41Z", + "contentLanguages": [ + "en" + ], + "sender": { + "id": "unknown" + } + } +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/metadataset.json b/sdmx-json20/src/test/resources/serialization.expected/metadataset.json new file mode 100644 index 0000000..84c399f --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/metadataset.json @@ -0,0 +1,47 @@ +{ + "metadataflow": "urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=EPM:MetadataSet(1.8)", + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "type": "type1" + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "reportingEnd": "2022", + "validFrom": "2022-07-17T10:11:16Z", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "targets": [ + "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataSet=EPM:MetadataSetTar(1.8)" + ], + "reportingBegin": "2022", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "publicationPeriod": "2022-03", + "publicationYear": "2022", + "action": "Append", + "attributes": [ + { + "id": "attr1", + "value": "someVal", + "attributes": [ + { + "id": "attr2", + "value": "someVal2" + } + ] + } + ], + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16Z" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/organisation-scheme-map.json b/sdmx-json20/src/test/resources/serialization.expected/organisation-scheme-map.json new file mode 100644 index 0000000..d12ce52 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/organisation-scheme-map.json @@ -0,0 +1,52 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "itemMaps": [ + { + "annotations": [ + { + "id": "Ann" + } + ], + "sourceValue": "S-1", + "targetValue": "IM-1", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + }, + { + "annotations": [ + { + "id": "Ann" + } + ], + "sourceValue": "S-2", + "targetValue": "IM-2", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + } + ], + "source": "urn:sdmx:org.sdmx.infomodel.base.AgencyScheme=SDMX:AGENCIES(1.0)", + "target": "urn:sdmx:org.sdmx.infomodel.base.AgencyScheme=SDMX:AGENCIES(1.0)" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/organisation-unit-scheme.json b/sdmx-json20/src/test/resources/serialization.expected/organisation-unit-scheme.json new file mode 100644 index 0000000..9c32424 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/organisation-unit-scheme.json @@ -0,0 +1,96 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.0", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "isPartial": true, + "organisationUnits": [ + { + "annotations": [ + { + "id": "Annot" + } + ], + "id": "OrgUnit", + "name": "OrganisationUnit", + "names": { + "en": "OrganisationUnit" + }, + "description": "OrganisationUnit description", + "descriptions": { + "en": "OrganisationUnit description" + }, + "contacts": [ + { + "name": "AG_1", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + }, + { + "name": "AG_2", + "department": "IT", + "role": { + "en": "writing", + "fr": "ecrire" + }, + "telephones": [ + "9458673082" + ], + "faxes": [ + "somedatafax2" + ], + "x400s": [ + "X400" + ], + "emails": [ + "test@email.com" + ] + } + ] + }, + { + "annotations": [], + "id": "OrgUnit2", + "parent": "OrgUnit", + "name": "OrganisationUnit", + "names": { + "en": "OrganisationUnit" + } + } + ] +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/process.json b/sdmx-json20/src/test/resources/serialization.expected/process.json new file mode 100644 index 0000000..edfb594 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/process.json @@ -0,0 +1,107 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "processSteps": [ + { + "annotations": [ + { + "id": "Annot" + } + ], + "id": "ProcStep", + "name": "ProcessStep", + "names": { + "en": "ProcessStep" + }, + "description": "ProcessStep description", + "descriptions": { + "en": "ProcessStep description" + }, + "computation": { + "localID": "LocId", + "softwareLanguage": "SoftwareLanguage", + "softwarePackage": "SoftwarePackage", + "softwareVersion": "SoftwareVersion", + "annotations": [ + { + "id": "Annot" + } + ], + "description": "Computation Description", + "descriptions": { + "en": "Computation Description" + } + }, + "transitions": [ + { + "annotations": [], + "id": "Trans", + "localID": "Loc", + "condition": "Doo", + "conditions": { + "en": "Doo" + }, + "targetStep": "ST" + } + ], + "outputs": [ + { + "localID": "Loc", + "annotations": [ + { + "id": "Annot" + } + ], + "objectReference": "urn:sdmx:org.sdmx.infomodel.process.ProcessStep=IMF:Artefact(1.0)" + } + ], + "inputs": [ + { + "localID": "Loc", + "annotations": [ + { + "id": "Annot" + } + ], + "objectReference": "urn:sdmx:org.sdmx.infomodel.process.ProcessStep=IMF:Artefact(1.0)" + } + ], + "processSteps": [ + { + "annotations": [ + { + "id": "Annot" + } + ], + "id": "ProcessChild", + "name": "ProcessStepChild", + "names": { + "en": "ProcessStepChild" + } + } + ] + } + ] +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/provision-agreement.json b/sdmx-json20/src/test/resources/serialization.expected/provision-agreement.json new file mode 100644 index 0000000..1079ecf --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/provision-agreement.json @@ -0,0 +1,28 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "dataProvider": "urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP", + "dataflow": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=IMF:ARTEFACT(1.2)" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/reporting-taxonomy-map.json b/sdmx-json20/src/test/resources/serialization.expected/reporting-taxonomy-map.json new file mode 100644 index 0000000..0f6faf7 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/reporting-taxonomy-map.json @@ -0,0 +1,52 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "itemMaps": [ + { + "annotations": [ + { + "id": "Ann" + } + ], + "sourceValue": "S-1", + "targetValue": "IM-1", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + }, + { + "annotations": [ + { + "id": "Ann" + } + ], + "sourceValue": "S-2", + "targetValue": "IM-2", + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + } + ], + "source": "urn:sdmx:org.sdmx.infomodel.categoryscheme.ReportingTaxonomy=SDMX:REP_SOURCE(1.0)", + "target": "urn:sdmx:org.sdmx.infomodel.categoryscheme.ReportingTaxonomy=SDMX:REP_TARGET(1.0)" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/reporting-taxonomy.json b/sdmx-json20/src/test/resources/serialization.expected/reporting-taxonomy.json new file mode 100644 index 0000000..1fd747e --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/reporting-taxonomy.json @@ -0,0 +1,71 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "isPartial": false, + "reportingCategories": [ + { + "annotations": [ + { + "id": "Annot" + } + ], + "id": "RC-1", + "name": "ReportingCat", + "names": { + "en": "ReportingCat" + }, + "description": "ReportingCat description", + "descriptions": { + "en": "ReportingCat description" + }, + "provisioningMetadata": [ + "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataS2(3.0)", + "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataS1(3.0)" + ], + "reportingCategories": [ + { + "annotations": [ + { + "id": "Annot" + } + ], + "id": "RC-2", + "name": "ReportingCat2", + "names": { + "en": "ReportingCat2" + }, + "description": "ReportingCat2 description", + "descriptions": { + "en": "ReportingCat2 description" + }, + "structuralMetadata": [ + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=EPM:DataS2(3.0)", + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=EPM:DataS1(3.0)" + ] + } + ] + } + ] +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/representation-map.json b/sdmx-json20/src/test/resources/serialization.expected/representation-map.json new file mode 100644 index 0000000..bab4376 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/representation-map.json @@ -0,0 +1,58 @@ +{ + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "type": "type1" + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16Z", + "source": [ + { + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_SOURCE(1.0)" + }, + { + "dataType": "DateTime" + } + ], + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "target": [ + { + "codelist": "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_TARGET(1.0)" + } + ], + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "representationMappings": [ + { + "targetValues": [ + "targetValue1", + "targetValue2" + ], + "sourceValues": [ + { + "startIndex": 0, + "isRegEx": true, + "endIndex": 10, + "value": "mappedValue" + } + ], + "annotations": [], + "validFrom": "2022-07-17T00:00:00Z", + "validTo": "2022-07-17T00:00:00Z" + } + ], + "name": "Maintanable artefact", + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16Z" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/structure-map-with-null-map.json b/sdmx-json20/src/test/resources/serialization.expected/structure-map-with-null-map.json new file mode 100644 index 0000000..234cc77 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/structure-map-with-null-map.json @@ -0,0 +1,56 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "epochMaps": [], + "datePatternMaps": [], + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_3", + "datePattern": "2022-11", + "annotations": [], + "id": "FR3" + }, + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "annotations": [], + "id": "FR1" + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "annotations": [], + "id": "FR2" + } + ], + "fixedValueMaps": [ + { + "annotations": [], + "value": "value" + } + ] +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/structure-map-with-null-target-source.json b/sdmx-json20/src/test/resources/serialization.expected/structure-map-with-null-target-source.json new file mode 100644 index 0000000..0469620 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/structure-map-with-null-target-source.json @@ -0,0 +1,111 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "epochMaps": [ + { + "annotations": [], + "id": "EPOCH1", + "mappedComponents": [ + { + "source": "CompMapEpochS", + "target": "CompMapEpochT" + } + ], + "resolvePeriod": "MID_PERIOD", + "frequencyDimension": "Frequency_dim", + "mappedFrequencies": [ + "FR3" + ], + "yearStart": {}, + "basePeriod": "2022-07-17T10:11:16Z", + "epochPeriod": "MICROSECOND" + } + ], + "datePatternMaps": [ + { + "annotations": [], + "id": "DP1", + "mappedComponents": [ + { + "source": "CompMapDPS", + "target": "CompMapDPT" + } + ], + "resolvePeriod": "MID_PERIOD", + "frequencyDimension": "Frequency_dim", + "mappedFrequencies": [ + "FR1", + "FR2" + ], + "yearStart": {}, + "locale": "EN", + "sourcePattern": "SOURCE" + } + ], + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_3", + "datePattern": "2022-11", + "annotations": [], + "id": "FR3" + }, + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "annotations": [], + "id": "FR1" + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "annotations": [], + "id": "FR2" + } + ], + "componentMaps": [ + { + "annotations": [], + "source": [ + "CompMapRepS" + ], + "target": [ + "CompMapRepT" + ], + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)" + }, + { + "annotations": [], + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)" + } + ], + "fixedValueMaps": [ + { + "annotations": [], + "value": "value" + } + ] +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/structure-map.json b/sdmx-json20/src/test/resources/serialization.expected/structure-map.json new file mode 100644 index 0000000..427082c --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/structure-map.json @@ -0,0 +1,107 @@ +{ + "frequencyFormatMappings": [ + { + "frequencyId": "CODE_3", + "datePattern": "2022-11", + "annotations": [], + "id": "FR3" + }, + { + "frequencyId": "CODE_1", + "datePattern": "2022-11", + "annotations": [], + "id": "FR1" + }, + { + "frequencyId": "CODE_2", + "datePattern": "2022-11", + "annotations": [], + "id": "FR2" + } + ], + "datePatternMaps": [ + { + "mappedFrequencies": [ + "FR1", + "FR2" + ], + "mappedComponents": [ + { + "source": "CompMapDPS", + "target": "CompMapDPT" + } + ], + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "DP1", + "locale": "EN", + "frequencyDimension": "Frequency_dim", + "yearStart": {}, + "sourcePattern": "SOURCE" + } + ], + "fixedValueMaps": [ + { + "annotations": [], + "value": "value" + } + ], + "epochMaps": [ + { + "mappedFrequencies": [ + "FR3" + ], + "basePeriod": "2022-07-17T10:11:16Z", + "mappedComponents": [ + { + "source": "CompMapEpochS", + "target": "CompMapEpochT" + } + ], + "epochPeriod": "MICROSECOND", + "resolvePeriod": "MID_PERIOD", + "annotations": [], + "id": "EPOCH1", + "frequencyDimension": "Frequency_dim", + "yearStart": {} + } + ], + "componentMaps": [ + { + "representationMap": "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)", + "annotations": [], + "source": [ + "CompMapRepS" + ], + "target": [ + "CompMapRepT" + ] + } + ], + "annotations": [ + { + "texts": { + "en": "text" + }, + "id": "1", + "text": "text", + "type": "type1" + } + ], + "description": "Some artefact", + "agencyID": "IMF", + "validFrom": "2022-07-17T10:11:16Z", + "source": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0)", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "target": "urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0)", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "name": "Maintanable artefact", + "id": "ARTEFACT", + "validTo": "2022-07-17T10:11:16Z" +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/structure.json b/sdmx-json20/src/test/resources/serialization.expected/structure.json new file mode 100644 index 0000000..20fbab1 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/structure.json @@ -0,0 +1,110 @@ +{ + "data": { + "categorisations": [ + { + "annotations": [], + "description": "categ", + "agencyID": "EPM", + "id": "catid", + "source": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Categorisation=IMF:ARTEFACT(1.2).CAT_SOURCE", + "descriptions": { + "en": "categ" + }, + "version": "1.0", + "target": "urn:sdmx:org.sdmx.infomodel.categoryscheme.Category=IMF:ARTEFACT(1.2).CAT_TARGET" + } + ], + "dataStructures": [ + { + "annotations": [], + "id": "DSD1", + "version": "1.0" + } + ], + "hierarchies": [ + { + "annotations": [], + "hierarchicalCodes": [], + "id": "Hi1", + "version": "1.0", + "hasFormalLevels": false + } + ], + "representationMaps": [ + { + "representationMappings": [], + "annotations": [], + "id": "RM1", + "version": "1.0" + } + ], + "metadataStructures": [ + { + "metadataStructureComponents": {}, + "annotations": [], + "id": "MDSD1", + "version": "1.0" + } + ], + "categorySchemes": [ + { + "annotations": [], + "isPartial": false, + "id": "CS1", + "categories": [], + "version": "1.0" + } + ], + "codelists": [ + { + "annotations": [], + "isPartial": false, + "id": "CL1", + "version": "1.0", + "codelistExtensions": [] + } + ], + "conceptSchemes": [ + { + "concepts": [], + "isPartial": false, + "annotations": [], + "id": "CS1", + "version": "1.0" + }, + { + "concepts": [], + "isPartial": false, + "annotations": [], + "id": "CS2", + "version": "1.0" + } + ], + "dataflows": [ + { + "annotations": [], + "id": "DF1", + "version": "1.0" + } + ], + "metadataflows": [ + { + "annotations": [], + "id": "MF1", + "version": "1.0" + } + ] + }, + "meta": { + "schema": "https://raw.githubusercontent.com/sdmx-twg/sdmx-json/master/metadata-message/tools/schemas/2.0.0/sdmx-json-metadata-schema.json", + "test": false, + "sender": { + "id": "unknown" + }, + "prepared": "2022-04-03T15:35:01Z", + "contentLanguages": [ + "en" + ], + "id": "IDREF7553" + } +} diff --git a/sdmx-json20/src/test/resources/serialization.expected/valuelist.json b/sdmx-json20/src/test/resources/serialization.expected/valuelist.json new file mode 100644 index 0000000..00c5777 --- /dev/null +++ b/sdmx-json20/src/test/resources/serialization.expected/valuelist.json @@ -0,0 +1,62 @@ +{ + "annotations": [ + { + "id": "1", + "type": "type1", + "text": "text", + "texts": { + "en": "text" + } + } + ], + "id": "ARTEFACT", + "name": "Maintanable artefact", + "names": { + "en": "Maintanable artefact", + "fr-CA": "artefact" + }, + "description": "Some artefact", + "descriptions": { + "en": "Some artefact" + }, + "version": "1.2", + "validTo": "2022-07-17T10:11:16Z", + "validFrom": "2022-07-17T10:11:16Z", + "agencyID": "IMF", + "valueItems": [ + { + "annotations": [ + { + "id": "Annot" + } + ], + "id": "VAL-1", + "name": "Maintanable artefact", + "names": { + "en": "value", + "fr": "val" + }, + "description": "it is value", + "descriptions": { + "en": "it is value", + "fr": "c'est val" + } + }, + { + "annotations": [ + { + "id": "Annot" + } + ], + "id": "VAL-2", + "name": "Maintanable artefact", + "names": { + "en": "smth" + }, + "description": "smth description", + "descriptions": { + "en": "smth description" + } + } + ] +} diff --git a/sdmx-ml21/build.gradle b/sdmx-ml21/build.gradle new file mode 100644 index 0000000..6cd7227 --- /dev/null +++ b/sdmx-ml21/build.gradle @@ -0,0 +1,50 @@ +plugins { + id 'java' +} + +repositories { + mavenCentral() +} + +dependencies { + compileOnly("org.projectlombok:lombok:${lombok_version}") + + annotationProcessor("org.projectlombok:lombok:${lombok_version}") + annotationProcessor("org.mapstruct:mapstruct-processor:${mapstruct_version}") + + implementation project(":sdmx30-infomodel") + implementation project(":sdmx30-serializer") + + implementation("org.apache.logging.log4j:log4j-slf4j2-impl:${log4j_version}") + implementation("org.apache.logging.log4j:log4j-core:${log4j_version}") + implementation("com.epam.deltix:SdmxDataParser:${sdmx_version}") + implementation("org.mapstruct:mapstruct:${mapstruct_version}") + implementation("org.apache.commons:commons-collections4:${org_apache_commons_commons_collections4_version}") + implementation("org.apache.commons:commons-lang3:${org_apache_commons_commons_lang3_version}") + implementation("com.fasterxml.jackson.core:jackson-core:${fasterxml_version}") + implementation("com.fasterxml.jackson.core:jackson-databind:${fasterxml_databind_version}") + implementation("com.google.guava:guava:${guava_version}") + implementation("org.glassfish.jaxb:jaxb-runtime:${xml_bind_jaxb_version}") + + testAnnotationProcessor("org.projectlombok:lombok:${lombok_version}") + + testImplementation("org.springframework:spring-core:${spring_version}") + testImplementation("org.projectlombok:lombok:${lombok_version}") + testImplementation("commons-io:commons-io:2.14.0") + testImplementation("io.github.benas:random-beans:${random_beans_version}") + testImplementation("org.assertj:assertj-core:${assertj_version}") + testImplementation("org.mockito:mockito-core:${mockito_version}") + testImplementation("org.xmlunit:xmlunit-legacy:${xmlunit_legacy_version}") + testImplementation("com.epam.deltix:SdmxApi:${sdmx_version}") + testImplementation("com.epam.deltix:SdmxBeans:${sdmx_version}") + testImplementation("com.epam.deltix:SdmxDataParser:${sdmx_version}") + testImplementation("com.epam.deltix:SdmxFileQueryProcessor:${sdmx_version}") + testImplementation("com.epam.deltix:SdmxQueryBuilder:${sdmx_version}") + testImplementation("com.epam.deltix:SdmxSourceUtil:${sdmx_version}") + testImplementation("com.epam.deltix:SdmxStructureParser:${sdmx_version}") + testImplementation("com.epam.deltix:SdmxStructureRetrieval:${sdmx_version}") +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/AnnotableWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/AnnotableWriter.java new file mode 100644 index 0000000..b367dc6 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/AnnotableWriter.java @@ -0,0 +1,56 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.AnnotableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.Annotation; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.InternationalUri; + +import org.apache.commons.collections4.CollectionUtils; + +public class AnnotableWriter { + + protected void write(List annotations, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isEmpty(annotations)) { + return; + } + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.COM_ANNOTATIONS); + for (Annotation annotation : annotations) { + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.COM_ANNOTATION); + String id = annotation.getId(); + if (id != null) { + writer.writeAttribute(XmlConstants.ID, id); + } + + String title = annotation.getTitle(); + if (title != null) { + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.COM_ANNOTATION_TITLE); + writer.writeCharacters(title); + writer.writeEndElement(); + } + + String type = annotation.getType(); + if (type != null) { + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.COM_ANNOTATION_TYPE); + writer.writeCharacters(type); + writer.writeEndElement(); + } + + InternationalUri url = annotation.getUrl(); + XmlWriterUtils.writeInternationalUri(url, writer, XmlConstants.COMMON + XmlConstants.COM_ANNOTATION_URL); + + InternationalString text = annotation.getText(); + XmlWriterUtils.writeInternationalString(text, writer, XmlConstants.COMMON + XmlConstants.COM_ANNOTATION_TEXT); + writer.writeEndElement(); + } + writer.writeEndElement(); + } + + public void write(AnnotableArtefact artefact, XMLStreamWriter writer) throws XMLStreamException { + write(artefact.getAnnotations(), writer); + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/AttributeListWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/AttributeListWriter.java new file mode 100644 index 0000000..e19c53b --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/AttributeListWriter.java @@ -0,0 +1,128 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.AttributeRelationship; +import com.epam.jsdmx.infomodel.sdmx30.DataAttribute; +import com.epam.jsdmx.infomodel.sdmx30.DimensionRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.GroupRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.ObservationRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.Representation; + +import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; + +@AllArgsConstructor +public class AttributeListWriter { + + private final AnnotableWriter annotableWriter; + private final RepresentationWriter representationWriter; + private final ReferenceWriter referenceWriter; + + public void writeAttributeList(AttributeDescriptor attributeDescriptor, XMLStreamWriter writer) throws XMLStreamException { + if (attributeDescriptor != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.ATTRIBUTE_LIST); + + XmlWriterUtils.writeIdUriAttributes(writer, XmlConstants.ATTRIBUTE_DESCRIPTOR_ID, attributeDescriptor.getUri()); + if (attributeDescriptor.getContainer() != null) { + XmlWriterUtils.writeUrn(attributeDescriptor.getUrn(), writer); + } + + annotableWriter.write(attributeDescriptor, writer); + List components = attributeDescriptor.getComponents(); + writeAttribute(components, writer); + writer.writeEndElement(); + } + + } + + private void writeAttribute(List components, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(components)) { + for (DataAttribute attribute : components) { + writeAttribute(writer, attribute); + } + } + } + + private void writeAttribute(XMLStreamWriter writer, DataAttribute attribute) throws XMLStreamException { + if (attribute != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.ATTRIBUTE); + XmlWriterUtils.writeIdUriAttributes(writer, attribute.getId(), attribute.getUri()); + if (attribute.getContainer() != null) { + XmlWriterUtils.writeUrn(attribute.getUrn(), writer); + } + boolean mandatory = attribute.isMandatory(); + writer.writeAttribute(XmlConstants.ASSIGNMENT_STATUS, mandatory ? XmlConstants.MANDATORY : XmlConstants.CONDITIONAL); + this.annotableWriter.write(attribute, writer); + referenceWriter.writeConceptIdentity(writer, attribute); + Representation localRepresentation = attribute.getLocalRepresentation(); + if (localRepresentation != null) { + representationWriter.writeRepresentation(writer, localRepresentation, XmlConstants.LOCAL_REPRESENTATION); + } + referenceWriter.writeConceptRoles(writer, attribute.getConceptRoles()); + writeAttributeRelationship(writer, attribute.getAttributeRelationship()); + writer.writeEndElement(); + } + } + + private void writeAttributeRelationship(XMLStreamWriter writer, AttributeRelationship attributeRelationship) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STR + XmlConstants.ATTRIBUTE_RELATIONSHIP); + if (attributeRelationship == null) { + writer.writeEmptyElement(XmlConstants.STR + XmlConstants.NONE_RELATIONSHIP); + } else if (attributeRelationship instanceof DimensionRelationshipImpl) { + DimensionRelationshipImpl dimensionRelationship = (DimensionRelationshipImpl) attributeRelationship; + writeDimensions(writer, dimensionRelationship); + writeAttachmentGroups(writer, dimensionRelationship); + } else if (attributeRelationship instanceof ObservationRelationshipImpl) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.PRIMARY_MEASURE); + writeLocalRef(writer, XmlConstants.OBS_VALUE); + writer.writeEndElement(); + } else if (attributeRelationship instanceof GroupRelationshipImpl) { + GroupRelationshipImpl groupRelationship = (GroupRelationshipImpl) attributeRelationship; + writeGroup(writer, groupRelationship); + } + writer.writeEndElement(); + } + + private void writeLocalRef(XMLStreamWriter writer, String value) throws XMLStreamException { + referenceWriter.writeLocalReference(writer, value); + } + + private void writeGroup(XMLStreamWriter writer, GroupRelationshipImpl groupRelationship) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STR + XmlConstants.GROUP); + if (groupRelationship.getGroupKey() != null) { + referenceWriter.writeLocalReference(writer, groupRelationship.getGroupKey()); + } + writer.writeEndElement(); + } + + private void writeDimensions(XMLStreamWriter writer, DimensionRelationshipImpl dimensionRelationship) throws XMLStreamException { + List dimensions = dimensionRelationship.getDimensions(); + if (CollectionUtils.isNotEmpty(dimensions)) { + for (String dimension : dimensions) { + if (dimension != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.DIMENSION); + writeLocalRef(writer, dimension); + writer.writeEndElement(); + } + } + } + } + + private void writeAttachmentGroups(XMLStreamWriter writer, DimensionRelationshipImpl relationship) throws XMLStreamException { + List groupKeys = relationship.getGroupKeys(); + if (CollectionUtils.isNotEmpty(groupKeys)) { + for (String key : groupKeys) { + if (key != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.ATTACHMENT_GROUP); + writeLocalRef(writer, key); + writer.writeEndElement(); + } + } + } + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CategorisationWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CategorisationWriter.java new file mode 100644 index 0000000..a8d84e4 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CategorisationWriter.java @@ -0,0 +1,62 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Categorisation; + + +public class CategorisationWriter extends XmlWriter { + + private final ReferenceWriter referenceWriter; + + public CategorisationWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + ReferenceWriter referenceWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter); + this.referenceWriter = referenceWriter; + } + + @Override + protected void writeAttributes(Categorisation categorisation, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(categorisation, writer); + } + + @Override + protected void writeCustomAttributeElements(Categorisation categorisation, XMLStreamWriter writer) throws XMLStreamException { + + ArtefactReference categorizedArtefact = categorisation.getCategorizedArtefact(); + ArtefactReference categorizedBy = categorisation.getCategorizedBy(); + if (categorizedArtefact != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.SOURCE); + referenceWriter.writeObjectReference(writer, categorizedArtefact); + writer.writeEndElement(); + } + + if (categorizedBy != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.TARGET); + referenceWriter.writeCategoryReference(writer, categorizedBy); + writer.writeEndElement(); + } + } + + @Override + protected String getName(Categorisation unused) { + return XmlConstants.CATEGORISATION; + } + + @Override + protected String getNamePlural() { + return XmlConstants.CATEGORISATIONS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getCategorisations(); + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CategorySchemeWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CategorySchemeWriter.java new file mode 100644 index 0000000..39a8b5c --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CategorySchemeWriter.java @@ -0,0 +1,64 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Category; +import com.epam.jsdmx.infomodel.sdmx30.CategoryScheme; + +import org.apache.commons.collections4.CollectionUtils; + +public class CategorySchemeWriter extends XmlWriter { + + public CategorySchemeWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter); + } + + @Override + protected void writeAttributes(CategoryScheme categoryScheme, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(categoryScheme, writer); + writer.writeAttribute(XmlConstants.IS_PARTIAL, String.valueOf(categoryScheme.isPartial())); + } + + @Override + protected void writeCustomAttributeElements(CategoryScheme categoryScheme, XMLStreamWriter writer) throws XMLStreamException { + writeCategory(categoryScheme.getItems(), writer); + } + + @Override + protected String getName(CategoryScheme unused) { + return XmlConstants.CATEGORY_SCHEME; + } + + @Override + protected String getNamePlural() { + return XmlConstants.CATEGORY_SCHEMES; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getCategorySchemes(); + } + + private void writeCategory(List items, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(items)) { + for (Category category : items) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.CATEGORY); + XmlWriterUtils.writeIdUriAttributes(writer, category.getId(), category.getUri()); + if (category.getContainer() != null) { + writer.writeAttribute(XmlConstants.URN, category.getUrn()); + } + this.annotableWriter.write(category, writer); + this.nameableWriter.write(category, writer); + writeCategory(category.getHierarchy(), writer); + writer.writeEndElement(); + } + } + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CodeWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CodeWriter.java new file mode 100644 index 0000000..3415e3b --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CodeWriter.java @@ -0,0 +1,59 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.net.URI; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Code; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public abstract class CodeWriter { + + private final ReferenceWriter referenceWriter; + private final NameableWriter nameableWriter; + private final AnnotableWriter annotableWriter; + + void write(T code, + XMLStreamWriter writer, + String name) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STR + name); + writeAttributes(code, writer); + writeElements(code, writer); + writer.writeEndElement(); + } + + void writeAttributes(T code, XMLStreamWriter writer) throws XMLStreamException { + String id = code.getId(); + if (id != null) { + writer.writeAttribute(XmlConstants.ID, id); + } + + URI uri = code.getUri(); + if (uri != null) { + writer.writeAttribute(XmlConstants.URI, uri.toString()); + } + + if (code.getContainer() != null) { + String urn = code.getUrn(); + if (urn != null) { + referenceWriter.writeUrnAttribute(writer, urn); + } + } + } + + void writeElements(T code, + XMLStreamWriter writer) throws XMLStreamException { + String parentId = code.getParentId(); + annotableWriter.write(code, writer); + nameableWriter.write(code, writer); + + if (parentId != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.STRUCTURE_PARENT); + referenceWriter.writeLocalReference(writer, parentId); + writer.writeEndElement(); + } + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CodeWriterImpl.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CodeWriterImpl.java new file mode 100644 index 0000000..e0afc91 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CodeWriterImpl.java @@ -0,0 +1,11 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import com.epam.jsdmx.infomodel.sdmx30.Code; + +public class CodeWriterImpl extends CodeWriter { + public CodeWriterImpl(ReferenceWriter referenceWriter, + NameableWriter nameableWriter, + AnnotableWriter annotableWriter) { + super(referenceWriter, nameableWriter, annotableWriter); + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CodelistWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CodelistWriter.java new file mode 100644 index 0000000..daaef13 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CodelistWriter.java @@ -0,0 +1,62 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Code; +import com.epam.jsdmx.infomodel.sdmx30.Codelist; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; + +public class CodelistWriter extends XmlWriter { + + private final CodeWriterImpl codeWriterImpl; + + public CodelistWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + CodeWriterImpl codeWriterImpl) { + super(nameableWriter, annotableWriter, commonAttributesWriter); + this.codeWriterImpl = codeWriterImpl; + } + + @Override + protected void writeAttributes(Codelist codelist, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(codelist, writer); + writer.writeAttribute(XmlConstants.IS_PARTIAL, String.valueOf(codelist.isPartial())); + } + + public Set extractArtefacts(Artefacts artefacts) { + return artefacts.getCodelists(); + } + + @Override + protected String getName(Codelist unused) { + return XmlConstants.CODELIST; + } + + @Override + protected String getNamePlural() { + return XmlConstants.CODELISTS; + } + + @Override + public Optional getWritableArtefactStructureClass() { + return Optional.of(StructureClassImpl.CODELIST); + } + + @Override + protected void writeCustomAttributeElements(Codelist codelist, XMLStreamWriter writer) throws XMLStreamException { + List codes = codelist.getItems(); + for (Code code : codes) { + if (code != null) { + codeWriterImpl.write(code, writer, XmlConstants.STR_CODE); + } + } + } +} \ No newline at end of file diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CommonAttributesWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CommonAttributesWriter.java new file mode 100644 index 0000000..a2036ed --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CommonAttributesWriter.java @@ -0,0 +1,73 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static com.epam.jsdmx.serializer.util.DateTimeConverterUtil.convertToDateTime; + +import java.net.URI; +import java.net.URL; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.Version; + + +public class CommonAttributesWriter { + + private final ReferenceWriter referenceWriter; + + public CommonAttributesWriter(ReferenceWriter referenceWriter) { + this.referenceWriter = referenceWriter; + } + + public void writeAttributes(MaintainableArtefact artefact, + XMLStreamWriter writer) throws XMLStreamException { + + writeAttributes( + artefact.getId(), + artefact.getOrganizationId(), + artefact.getUri(), + artefact.getUrn(), + artefact.getVersion(), + artefact.isExternalReference(), + artefact.getServiceUrl(), + artefact.getStructureUrl(), + artefact.getValidToString(), + artefact.getValidFromString(), + writer + ); + } + + public void writeAttributes(String id, + String agencyId, + URI uri, + String urn, + Version version, + boolean isExternalReference, + URL serviceUrl, + URL structureUrl, + String validTo, + String validFrom, + XMLStreamWriter writer) throws XMLStreamException { + + XmlWriterUtils.writeUri(uri, writer); + + referenceWriter.writeUrn(writer, urn); + + XmlWriterUtils.writeMandatoryAttribute(agencyId, writer, XmlConstants.AGENCY_ID); + XmlWriterUtils.writeMandatoryAttribute(id, writer, XmlConstants.ID); + + XmlWriterUtils.writeVersion(version, writer); + XmlWriterUtils.writeIsFinal(writer, version); + + writer.writeAttribute(XmlConstants.IS_EXTERNAL_REFERENCE, String.valueOf(isExternalReference)); + + XmlWriterUtils.writeUrl(serviceUrl, writer, XmlConstants.SERVICE_URL); + XmlWriterUtils.writeUrl(structureUrl, writer, XmlConstants.STRUCTURE_URL); + + String validToDateTime = convertToDateTime(validTo); + String validFromDateTime = convertToDateTime(validFrom); + XmlWriterUtils.writeAttributeIfNotNull(validToDateTime, writer, XmlConstants.VALID_TO); + XmlWriterUtils.writeAttributeIfNotNull(validFromDateTime, writer, XmlConstants.VALID_FROM); + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ConceptSchemeWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ConceptSchemeWriter.java new file mode 100644 index 0000000..e92d7a7 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ConceptSchemeWriter.java @@ -0,0 +1,104 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Concept; +import com.epam.jsdmx.infomodel.sdmx30.ConceptScheme; +import com.epam.jsdmx.infomodel.sdmx30.IsoConceptReference; + +import org.apache.commons.collections4.CollectionUtils; + +public class ConceptSchemeWriter extends XmlWriter { + + private final RepresentationWriter representationWriter; + + public ConceptSchemeWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + RepresentationWriter representationWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter); + this.representationWriter = representationWriter; + } + + @Override + protected void writeAttributes(ConceptScheme conceptScheme, XMLStreamWriter writer) throws XMLStreamException { + commonAttributesWriter.writeAttributes(conceptScheme, writer); + writer.writeAttribute(XmlConstants.IS_PARTIAL, String.valueOf(conceptScheme.isPartial())); + } + + @Override + protected void writeCustomAttributeElements(ConceptScheme conceptScheme, XMLStreamWriter writer) throws XMLStreamException { + writeConcepts(conceptScheme, writer); + } + + @Override + protected String getName(ConceptScheme unused) { + return XmlConstants.CONCEPT_SCHEME; + } + + @Override + protected String getNamePlural() { + return XmlConstants.CONCEPT_SCHEMES; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getConceptSchemes(); + } + + private void writeConcepts(ConceptScheme conceptScheme, XMLStreamWriter writer) throws XMLStreamException { + List concepts = conceptScheme.getItems(); + if (CollectionUtils.isNotEmpty(concepts)) { + for (Concept concept : concepts) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.CONCEPT); + XmlWriterUtils.writeMandatoryAttribute(concept.getId(), writer, XmlConstants.ID); + if (concept.getContainer() != null) { + XmlWriterUtils.writeUrn(concept.getUrn(), writer); + } + XmlWriterUtils.writeUri(concept.getUri(), writer); + annotableWriter.write(concept, writer); + nameableWriter.write(concept, writer); + representationWriter.writeRepresentation(writer, concept.getCoreRepresentation(), XmlConstants.CORE_REPRESENTATION); + writeIsoConcept(writer, concept); + writer.writeEndElement(); + } + } + } + + + private void writeIsoConcept(XMLStreamWriter writer, Concept concept) throws XMLStreamException { + IsoConceptReference isoConceptReference = concept.getIsoConceptReference(); + if (isoConceptReference != null) { + + writer.writeStartElement(XmlConstants.STR + XmlConstants.ISOCONCEPT_REFERENCE); + + String conceptId = isoConceptReference.getConceptId(); + String agency = isoConceptReference.getAgency(); + String schemeId = isoConceptReference.getSchemeId(); + + if (agency != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.CONCEPT_AGENCY); + writer.writeCharacters(agency); + writer.writeEndElement(); + } + + if (schemeId != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.CONCEPT_SCHEME_ID); + writer.writeCharacters(schemeId); + writer.writeEndElement(); + } + + if (conceptId != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.CONCEPT_ID); + writer.writeCharacters(conceptId); + writer.writeEndElement(); + } + writer.writeEndElement(); + } + } +} \ No newline at end of file diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ContactWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ContactWriter.java new file mode 100644 index 0000000..a0e61c0 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ContactWriter.java @@ -0,0 +1,57 @@ +package com.epam.jsdmx.xml21.structure.writer; + + +import java.net.URI; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Contact; + +import org.apache.commons.collections4.CollectionUtils; + +public class ContactWriter { + + public void writeContacts(List contacts, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(contacts)) { + for (Contact contact : contacts) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.CONTACT); + + writeElement(writer, contact.getName(), XmlConstants.COMMON + XmlConstants.NAME); + writeElement(writer, contact.getOrganizationUnit(), XmlConstants.STR + XmlConstants.DEPARTMENT); + XmlWriterUtils.writeInternationalString(contact.getResponsibility(), writer, XmlConstants.STR + XmlConstants.ROLE); + + writeContactData(writer, contact.getTelephone(), XmlConstants.TELEPHONE); + writeContactData(writer, contact.getFax(), XmlConstants.FAX); + writeContactData(writer, contact.getX400(), XmlConstants.X_400); + URI uri = contact.getUri(); + if (uri != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.URI); + XmlWriterUtils.writeCharacters(uri.toString(), writer); + writer.writeEndElement(); + } + writeContactData(writer, contact.getEmail(), XmlConstants.EMAIL); + + writer.writeEndElement(); + } + } + } + + private void writeContactData(XMLStreamWriter writer, String data, String name) throws XMLStreamException { + if (data != null) { + writer.writeStartElement(XmlConstants.STR + name); + writer.writeCharacters(data); + writer.writeEndElement(); + } + } + + private void writeElement(XMLStreamWriter writer, String contactElement, String nameElement) throws XMLStreamException { + if (contactElement != null) { + writer.writeStartElement(nameElement); + writer.writeAttribute(XmlConstants.XML_LANG, "en"); + writer.writeCharacters(contactElement); + writer.writeEndElement(); + } + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ContentConstraintWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ContentConstraintWriter.java new file mode 100644 index 0000000..930c205 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ContentConstraintWriter.java @@ -0,0 +1,150 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Constraint; +import com.epam.jsdmx.infomodel.sdmx30.ConstraintRoleType; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.MetadataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; + +import org.apache.commons.collections4.CollectionUtils; + +public class ContentConstraintWriter extends XmlWriter { + + private final ReferenceWriter referenceWriter; + private final ReleaseCalenderWriter releaseCalenderWriter; + private final DataKeySetsWriter dataKeySetsWriter; + private final CubeRegionWriter cubeRegionWriter; + private final MetadataConstraintWriter metadataConstraintWriter; + + protected ContentConstraintWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + ReferenceWriter referenceWriter, + ReleaseCalenderWriter releaseCalenderWriter, + DataKeySetsWriter dataKeySetsWriter, + CubeRegionWriter cubeRegionWriter, + MetadataConstraintWriter metadataConstraintWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter); + this.referenceWriter = referenceWriter; + this.releaseCalenderWriter = releaseCalenderWriter; + this.dataKeySetsWriter = dataKeySetsWriter; + this.cubeRegionWriter = cubeRegionWriter; + this.metadataConstraintWriter = metadataConstraintWriter; + } + + @Override + protected void writeAttributes(Constraint artefact, XMLStreamWriter writer) throws XMLStreamException { + commonAttributesWriter.writeAttributes(artefact, writer); + ConstraintRoleType constraintRoleType = artefact.getConstraintRoleType(); + if (constraintRoleType != null) { + writer.writeAttribute(XmlConstants.ROLE_ATTR, XmlConstants.CONSTRAINT_ROLE_STRING.get(constraintRoleType)); + } + } + + @Override + protected void writeCustomAttributeElements(Constraint artefact, XMLStreamWriter writer) throws XMLStreamException { + List constrainedArtefacts = artefact.getConstrainedArtefacts(); + writeConstrainedArtefacts(writer, constrainedArtefacts); + + if (artefact instanceof DataConstraint) { + DataConstraint constraint = (DataConstraint) artefact; + releaseCalenderWriter.writeReleaseCalendar(writer, constraint.getReleaseCalendar()); + dataKeySetsWriter.writeDataKeySets(writer, constraint.getDataContentKeys()); + cubeRegionWriter.writeCubeRegions(writer, constraint.getCubeRegions()); + } else { + MetadataConstraint constraint = (MetadataConstraint) artefact; + releaseCalenderWriter.writeReleaseCalendar(writer, constraint.getReleaseCalendar()); + metadataConstraintWriter.writeMetadataTargetRegions(writer, constraint.getMetadataTargetRegions()); + } + } + + private void writeConstrainedArtefacts(XMLStreamWriter writer, List constrainedArtefacts) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(constrainedArtefacts)) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.CONSTRAINT_ATTACHMENT); + for (ArtefactReference constrained : constrainedArtefacts) { + writeArtefactReference(writer, constrained); + } + writer.writeEndElement(); + } + } + + private void writeArtefactReference(XMLStreamWriter writer, ArtefactReference constrained) throws XMLStreamException { + if (constrained != null) { + StructureClass maintainableStructureClass = constrained.getMaintainableStructureClass(); + String simpleName = maintainableStructureClass.getSimpleName(); + if (simpleName.equals(StructureClassImpl.DATA_PROVIDER.getSimpleName())) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.DATA_PROVIDER); + referenceWriter.writeObjectReference(writer, constrained); + writer.writeEndElement(); + } + if (simpleName.equals(StructureClassImpl.DATA_STRUCTURE.getSimpleName())) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.DATA_STRUCTURE); + referenceWriter.writeDataStructureReference(writer, constrained); + writer.writeEndElement(); + } + if (simpleName.equals(StructureClassImpl.DATAFLOW.getSimpleName())) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.DATAFLOW); + referenceWriter.writeDataflowReference(writer, constrained); + writer.writeEndElement(); + } + if (simpleName.equals(StructureClassImpl.METADATA_STRUCTURE.getSimpleName())) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.METADATA_STRUCTURE); + referenceWriter.writeMetaDataStructureReference(writer, constrained); + writer.writeEndElement(); + } + if (simpleName.equals(StructureClassImpl.METADATAFLOW.getSimpleName())) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.METADATAFLOW); + referenceWriter.writeMetaDataflowReference(writer, constrained); + writer.writeEndElement(); + } + if (simpleName.equals(StructureClassImpl.PROVISION_AGREEMENT.getSimpleName())) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.PROVISION_AGREEMENT); + referenceWriter.writeProvisionAgreementReference(writer, constrained); + writer.writeEndElement(); + } + if (simpleName.equals(StructureClassImpl.METADATA_PROVIDER.getSimpleName())) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.METADATA_PROVIDER); + referenceWriter.writeObjectReference(writer, constrained); + writer.writeEndElement(); + } + if (simpleName.equals(StructureClassImpl.METADATA_SET.getSimpleName())) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.METADATA_SET); + referenceWriter.writeMetadataSetReference(writer, constrained); + writer.writeEndElement(); + } + if (simpleName.equals(StructureClassImpl.METADATA_PROVISION_AGREEMENT.getSimpleName())) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.METADATA_PROVISION_AGREEMENT); + referenceWriter.writeMetaProvisionAgreementReference(writer, constrained); + writer.writeEndElement(); + } + } + } + + @Override + protected String getName(Constraint artefact) { + return XmlConstants.CONTENT_CONSTRAINT; + } + + @Override + protected String getNamePlural() { + return XmlConstants.CONSTRAINTS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + var constraints = new HashSet(); + constraints.addAll(artefacts.getDataConstraints()); + constraints.addAll(artefacts.getMetadataConstraints()); + return constraints; + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CubeRegionWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CubeRegionWriter.java new file mode 100644 index 0000000..cb65074 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/CubeRegionWriter.java @@ -0,0 +1,55 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.CubeRegion; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionKey; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; + +import org.apache.commons.collections4.CollectionUtils; + +public class CubeRegionWriter { + private final AnnotableWriter annotableWriter; + private final MemberSelectionWriter memberSelectionWriter; + + public CubeRegionWriter(AnnotableWriter annotableWriter, MemberSelectionWriter memberSelectionWriter) { + this.annotableWriter = annotableWriter; + this.memberSelectionWriter = memberSelectionWriter; + } + + public void writeCubeRegions(XMLStreamWriter writer, List cubeRegions) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(cubeRegions)) { + for (CubeRegion cubeRegion : cubeRegions) { + if (cubeRegion != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.CUBE_REGION); + writer.writeAttribute(XmlConstants.INCLUDE, String.valueOf(cubeRegion.isIncluded())); + annotableWriter.write(cubeRegion, writer); + List memberSelections = cubeRegion.getMemberSelections(); + List cubeRegionKeys = cubeRegion.getCubeRegionKeys(); + writeCubeRegionKeys(cubeRegionKeys, writer); + memberSelectionWriter.writeMemberSelections(writer, memberSelections); + writer.writeEndElement(); + } + } + } + } + + private void writeCubeRegionKeys(List cubeRegionKeys, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(cubeRegionKeys)) { + for (CubeRegionKey cubeRegionKey : cubeRegionKeys) { + if (cubeRegionKey != null) { + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.KEY_VALUE); + writer.writeAttribute(XmlConstants.ID, cubeRegionKey.getComponentId()); + writer.writeAttribute(XmlConstants.INCLUDE, String.valueOf(cubeRegionKey.isIncluded())); + memberSelectionWriter.writeSelectionValues(writer, cubeRegionKey.getSelectionValues()); + writer.writeEndElement(); + } + } + } + } + + +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DataKeySetsWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DataKeySetsWriter.java new file mode 100644 index 0000000..0817a9b --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DataKeySetsWriter.java @@ -0,0 +1,72 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ComponentValue; +import com.epam.jsdmx.infomodel.sdmx30.DataKey; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySet; + +import org.apache.commons.collections4.CollectionUtils; + +public class DataKeySetsWriter { + + private final AnnotableWriter annotableWriter; + private final MemberSelectionWriter memberSelectionWriter; + + public DataKeySetsWriter(AnnotableWriter annotableWriter, MemberSelectionWriter memberSelectionWriter) { + this.annotableWriter = annotableWriter; + this.memberSelectionWriter = memberSelectionWriter; + } + + public void writeDataKeySets(XMLStreamWriter writer, List dataKeySets) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(dataKeySets)) { + for (DataKeySet dataKeySet : dataKeySets) { + if (dataKeySet != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.DATA_KEY_SET); + writer.writeAttribute(XmlConstants.IS_INCLUDED, String.valueOf(dataKeySet.isIncluded())); + List keys = dataKeySet.getKeys(); + writeDataKeys(keys, writer); + writer.writeEndElement(); + } + } + } + } + + private void writeDataKeys(List keys, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(keys)) { + for (DataKey dataKey : keys) { + if (dataKey != null) { + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.KEY); + writer.writeAttribute(XmlConstants.INCLUDE, String.valueOf(dataKey.isIncluded())); + annotableWriter.write(dataKey, writer); + List keyValues = dataKey.getKeyValues(); + writeKeyValues(keyValues, writer); + writer.writeEndElement(); + } + } + } + } + + private void writeKeyValues(List keyValues, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(keyValues)) { + for (ComponentValue componentValue : keyValues) { + if (componentValue != null) { + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.KEY_VALUE); + + writer.writeAttribute(XmlConstants.ID, componentValue.getComponentId()); + writer.writeAttribute(XmlConstants.INCLUDE, String.valueOf(componentValue.isIncluded())); + + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.VALUE); + XmlWriterUtils.writeCharacters(componentValue.getValue(), writer); + writer.writeEndElement(); + + writer.writeEndElement(); + } + } + } + } + +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DataStructureDefinitionWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DataStructureDefinitionWriter.java new file mode 100644 index 0000000..93914fe --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DataStructureDefinitionWriter.java @@ -0,0 +1,79 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinition; +import com.epam.jsdmx.serializer.common.TimeDimensionLocalRepresentationAdapter; +import com.epam.jsdmx.serializer.sdmx21.DataStructure30To21ComponentAdapter; + +import org.apache.commons.collections4.CollectionUtils; + +public class DataStructureDefinitionWriter extends XmlWriter { + + private final AttributeListWriter attributeListWriter; + private final DimensionListWriter dimensionListWriter; + private final GroupDimensionListWriter groupDimensionListWriter; + private final MeasureListWriter measureListWriter; + private final DataStructure30To21ComponentAdapter dsdComponentAdapter; + private final TimeDimensionLocalRepresentationAdapter dsdLocalRepresentationAdapter; + + public DataStructureDefinitionWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + AttributeListWriter attributeListWriter, + DimensionListWriter dimensionListWriter, + MeasureListWriter measureListWriter, + GroupDimensionListWriter groupDimensionListWriter, + DataStructure30To21ComponentAdapter dsdComponentAdapter, + TimeDimensionLocalRepresentationAdapter dsdLocalRepresentationAdapter) { + super(nameableWriter, annotableWriter, commonAttributesWriter); + this.attributeListWriter = attributeListWriter; + this.dimensionListWriter = dimensionListWriter; + this.measureListWriter = measureListWriter; + this.groupDimensionListWriter = groupDimensionListWriter; + this.dsdComponentAdapter = dsdComponentAdapter; + this.dsdLocalRepresentationAdapter = dsdLocalRepresentationAdapter; + } + + @Override + protected void writeAttributes(DataStructureDefinition dsd, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(dsd, writer); + } + + @Override + protected void writeCustomAttributeElements(DataStructureDefinition dsd, XMLStreamWriter writer) throws XMLStreamException { + var adaptedDsd = dsdLocalRepresentationAdapter.adapt(dsd); + adaptedDsd = dsdComponentAdapter.recompose(adaptedDsd); + writeDataStructureComponents(adaptedDsd, writer); + } + + @Override + protected String getName(DataStructureDefinition unused) { + return XmlConstants.DATA_STRUCTURE; + } + + @Override + protected String getNamePlural() { + return XmlConstants.DATA_STRUCTURES; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getDataStructures(); + } + + private void writeDataStructureComponents(DataStructureDefinition dsd, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(dsd.getComponents())) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.DATA_STRUCTURE_COMPONENTS); + dimensionListWriter.writeDimensionList(dsd.getDimensionDescriptor(), writer); + groupDimensionListWriter.writeGroupDimensionList(dsd.getGroupDimensionDescriptors(), writer); + attributeListWriter.writeAttributeList(dsd.getAttributeDescriptor(), writer); + measureListWriter.writeMeasureList(dsd.getMeasureDescriptor(), writer); + writer.writeEndElement(); + } + } +} \ No newline at end of file diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DataflowWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DataflowWriter.java new file mode 100644 index 0000000..29ba73c --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DataflowWriter.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Dataflow; + +public class DataflowWriter extends XmlWriter { + + private final ReferenceWriter referenceWriter; + + public DataflowWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + ReferenceWriter referenceWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter); + this.referenceWriter = referenceWriter; + } + + @Override + protected void writeAttributes(Dataflow dataflow, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(dataflow, writer); + } + + @Override + protected void writeCustomAttributeElements(Dataflow dataflow, XMLStreamWriter writer) throws XMLStreamException { + ArtefactReference structure = dataflow.getStructure(); + if (structure != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.STRUCTURE_UPPER); + referenceWriter.writeDataStructureReference(writer, structure); + writer.writeEndElement(); + } + } + + @Override + protected String getName(Dataflow unused) { + return XmlConstants.DATAFLOW; + } + + @Override + protected String getNamePlural() { + return XmlConstants.DATAFLOWS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getDataflows(); + } +} \ No newline at end of file diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DimensionListWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DimensionListWriter.java new file mode 100644 index 0000000..da5f445 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/DimensionListWriter.java @@ -0,0 +1,106 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Dimension; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponent; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.infomodel.sdmx30.TimeDimension; + +import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; + +@AllArgsConstructor +public class DimensionListWriter { + private final AnnotableWriter annotableWriter; + private final RepresentationWriter representationWriter; + private final ReferenceWriter referenceWriter; + + public void writeDimensionList(DimensionDescriptor dimensionDescriptor, XMLStreamWriter writer) throws XMLStreamException { + if (dimensionDescriptor != null) { + List components = dimensionDescriptor.getComponents(); + writer.writeStartElement(XmlConstants.STR + XmlConstants.DIMENSION_LIST); + XmlWriterUtils.writeIdUriAttributes(writer, XmlConstants.DIMENSION_DESCRIPTOR_ID, dimensionDescriptor.getUri()); + if (dimensionDescriptor.getContainer() != null) { + XmlWriterUtils.writeUrn(dimensionDescriptor.getUrn(), writer); + } + annotableWriter.write(dimensionDescriptor, writer); + if (CollectionUtils.isNotEmpty(components)) { + List timeDimension = components.stream().filter(DimensionComponent::isTimeDimension).collect(Collectors.toList()); + List dimensions = (List) CollectionUtils.subtract(components, timeDimension); + writeDimensions(writer, dimensions); + writeTimeDimensions(writer, timeDimension); + } + writer.writeEndElement(); + } + } + + private void writeTimeDimensions(XMLStreamWriter writer, List timeDimensionComponents) throws XMLStreamException { + List timeDimensions = Optional.ofNullable(timeDimensionComponents) + .stream() + .flatMap(List::stream) + .filter(d -> TimeDimension.class.isAssignableFrom(d.getClass())) + .map(TimeDimension.class::cast) + .collect(Collectors.toList()); + + if (CollectionUtils.isNotEmpty(timeDimensions)) { + for (TimeDimension timeDimension : timeDimensions) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.TIME_DIMENSION); + XmlWriterUtils.writeIdUriAttributes(writer, timeDimension.getId(), timeDimension.getUri()); + if (timeDimension.getContainer() != null) { + XmlWriterUtils.writeUrn(timeDimension.getUrn(), writer); + } + + this.annotableWriter.write(timeDimension, writer); + referenceWriter.writeConceptIdentity(writer, timeDimension); + Representation localRepresentation = timeDimension.getLocalRepresentation(); + if (localRepresentation != null) { + representationWriter.writeRepresentation(writer, localRepresentation, XmlConstants.LOCAL_REPRESENTATION); + } + writer.writeEndElement(); + } + } + } + + private void writeDimensions(XMLStreamWriter writer, List dimensionComponents) throws XMLStreamException { + List dimensions = Optional.ofNullable(dimensionComponents) + .stream() + .flatMap(List::stream) + .filter(d -> Dimension.class.isAssignableFrom(d.getClass())) + .map(Dimension.class::cast) + .collect(Collectors.toList()); + + if (CollectionUtils.isNotEmpty(dimensions)) { + for (Dimension dimension : dimensions) { + writeDimension(writer, dimension); + } + } + } + + private void writeDimension(XMLStreamWriter writer, Dimension dimension) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STR + XmlConstants.DIMENSION); + + XmlWriterUtils.writeIdUriAttributes(writer, dimension.getId(), dimension.getUri()); + if (dimension.getContainer() != null) { + XmlWriterUtils.writeUrn(dimension.getUrn(), writer); + } + writer.writeAttribute(XmlConstants.POSITION, String.valueOf(dimension.getOrder())); + this.annotableWriter.write(dimension, writer); + referenceWriter.writeConceptIdentity(writer, dimension); + Representation localRepresentation = dimension.getLocalRepresentation(); + if (localRepresentation != null) { + representationWriter.writeRepresentation(writer, localRepresentation, XmlConstants.LOCAL_REPRESENTATION); + } + List conceptRoles = dimension.getConceptRoles(); + referenceWriter.writeConceptRoles(writer, conceptRoles); + + writer.writeEndElement(); + } +} \ No newline at end of file diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/GroupDimensionListWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/GroupDimensionListWriter.java new file mode 100644 index 0000000..7a2222d --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/GroupDimensionListWriter.java @@ -0,0 +1,40 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.GroupDimensionDescriptor; + +import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; + +@AllArgsConstructor +public class GroupDimensionListWriter { + + private final AnnotableWriter annotableWriter; + private final ReferenceWriter referenceWriter; + + public void writeGroupDimensionList(List groupDimensionDescriptor, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isEmpty(groupDimensionDescriptor)) { + return; + } + + for (GroupDimensionDescriptor groupDimension : groupDimensionDescriptor) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.GROUP); + XmlWriterUtils.writeIdUriAttributes(writer, groupDimension.getId(), groupDimension.getUri()); + + this.annotableWriter.write(groupDimension, writer); + List groupDimensions = groupDimension.getDimensions(); + if (CollectionUtils.isNotEmpty(groupDimensions)) { + for (String groupDimensionName : groupDimensions) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.GROUP_DIMENSION); + referenceWriter.writeDimensionReference(writer, groupDimensionName); + writer.writeEndElement(); + } + } + writer.writeEndElement(); + } + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/HeaderWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/HeaderWriter.java new file mode 100644 index 0000000..7f1478d --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/HeaderWriter.java @@ -0,0 +1,77 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.time.Instant; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultHeaderProvider; +import com.epam.jsdmx.serializer.sdmx30.common.Header; + +import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; + +@AllArgsConstructor +public class HeaderWriter { + + DefaultHeaderProvider defaultHeaderProvider; + + public void writeDefaultHeader(XMLStreamWriter writer) throws XMLStreamException { + Header header = defaultHeaderProvider.provide(); + write(writer, header); + } + + public void write(XMLStreamWriter writer, Header header) throws XMLStreamException { + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.HEADER); + + String id = header.getId(); + if (id != null) { + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.MES_ID); + writer.writeCharacters(id); + writer.writeEndElement(); + } + + boolean test = header.isTest(); + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.MES_TEST); + writer.writeCharacters(String.valueOf(test)); + writer.writeEndElement(); + + Instant prepared = header.getPrepared(); + if (prepared != null) { + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.PREPARED); + writer.writeCharacters(prepared.toString()); + writer.writeEndElement(); + } + + Party sender = header.getSender(); + if (sender != null) { + String senderId = sender.getId(); + if (senderId != null) { + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.SENDER); + writer.writeAttribute(XmlConstants.ID, senderId); + InternationalString name = header.getName(); + XmlWriterUtils.writeInternationalString(name, writer, XmlConstants.COMMON + XmlConstants.COM_NAME); + writer.writeEndElement(); + } + } + + List receivers = header.getReceivers(); + if (CollectionUtils.isNotEmpty(receivers)) { + for (Party receiver : receivers) { + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.RECEIVER); + String receiverId = receiver.getId(); + if (receiverId != null) { + writer.writeAttribute(XmlConstants.ID, receiverId); + } + InternationalString name = header.getName(); + XmlWriterUtils.writeInternationalString(name, writer, XmlConstants.COMMON + XmlConstants.COM_NAME); + writer.writeEndElement(); + } + } + + writer.writeEndElement(); + } +} \ No newline at end of file diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/HierarchicalCodelistWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/HierarchicalCodelistWriter.java new file mode 100644 index 0000000..3f46ef4 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/HierarchicalCodelistWriter.java @@ -0,0 +1,320 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.net.URI; +import java.net.URL; +import java.time.Instant; +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Annotation; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CodingFormat; +import com.epam.jsdmx.infomodel.sdmx30.CrossReference; +import com.epam.jsdmx.infomodel.sdmx30.DeepEqualsExclusion; +import com.epam.jsdmx.infomodel.sdmx30.Facet; +import com.epam.jsdmx.infomodel.sdmx30.HierarchicalCode; +import com.epam.jsdmx.infomodel.sdmx30.Hierarchy; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.Level; +import com.epam.jsdmx.infomodel.sdmx30.Link; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; +import com.epam.jsdmx.infomodel.sdmx30.Version; + +import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; + + +public class HierarchicalCodelistWriter extends XmlWriter { + + private final ReferenceWriter referenceWriter; + + public HierarchicalCodelistWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + ReferenceWriter referenceWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter); + this.referenceWriter = referenceWriter; + } + + @Override + protected void writeAttributes(Hierarchy hierarchy, XMLStreamWriter writer) throws XMLStreamException { + commonAttributesWriter.writeAttributes(new HierarchyUrnAdapterWrapper(hierarchy), writer); + } + + @Override + protected void writeCustomAttributeElements(Hierarchy hierarchy, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(hierarchy.getCodes()) || hierarchy.getLevel() != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.HIERARCHY); + writer.writeAttribute(XmlConstants.ID, XmlConstants.HIERARCHY); + XmlWriterUtils.writeInternationalString(hierarchy.getName(), writer, XmlConstants.COMMON + XmlConstants.NAME); + writeHierarchicalCode(hierarchy.getCodes(), writer); + writeLevel(hierarchy.getLevel(), writer); + writer.writeEndElement(); + } + } + + @Override + protected String getName(Hierarchy unused) { + return XmlConstants.HIERARCHAL_CODELIST; + } + + @Override + protected String getNamePlural() { + return XmlConstants.HIERARCHICAL_CODELISTS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getHierarchies(); + } + + private void writeHierarchicalCode(List codes, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(codes)) { + for (HierarchicalCode code : codes) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.HIERARCHICAL_CODE); + writeHierarchicalCode(writer, code); + writer.writeEndElement(); + } + } + } + + private void writeHierarchicalCode(XMLStreamWriter writer, HierarchicalCode code) throws XMLStreamException { + + XmlWriterUtils.writeUri(code.getUri(), writer); + + if (code.getContainer() != null) { + XmlWriterUtils.writeUrn(code.getUrn(), writer); + } + + XmlWriterUtils.writeInstant(code.getValidTo(), writer, XmlConstants.VALID_TO); + XmlWriterUtils.writeInstant(code.getValidFrom(), writer, XmlConstants.VALID_FROM); + + XmlWriterUtils.writeMandatoryAttribute(code.getId(), writer, XmlConstants.ID); + + annotableWriter.write(code, writer); + ArtefactReference codeRef = code.getCode(); + if (codeRef != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.CODE); + referenceWriter.writeCodeReference(writer, codeRef); + writer.writeEndElement(); + } + + String levelId = code.getLevelId(); + if (levelId != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.LEVEL); + referenceWriter.writeLocalReference(writer, levelId); + writer.writeEndElement(); + } + + List hierarchicalCodes = code.getHierarchicalCodes(); + if (CollectionUtils.isNotEmpty(hierarchicalCodes)) { + writeHierarchicalCode(hierarchicalCodes, writer); + } + } + + private void writeLevel(Level level, XMLStreamWriter writer) throws XMLStreamException { + if (level != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.LEVEL); + writer.writeAttribute(XmlConstants.ID, level.getId()); + + if (level.getContainer() != null) { + writer.writeAttribute(XmlConstants.URN, level.getUrn()); + } + + URI uri = level.getUri(); + if (uri != null) { + writer.writeAttribute(XmlConstants.URI, uri.toString()); + } + annotableWriter.write(level, writer); + nameableWriter.write(level, writer); + List codeFormat = level.getCodeFormat(); + if (CollectionUtils.isNotEmpty(codeFormat)) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.CODING_FORMAT); + for (CodingFormat codingFormat : codeFormat) { + Facet facet = codingFormat.getCodingFormat(); + if (facet != null && facet.getType() != null) { + String value = XmlConstants.MAP_FACET_TYPE.get(facet.getType().name()); + writer.writeAttribute(value, facet.getValue()); + } + } + writer.writeEndElement(); + } + Level child = level.getChild(); + if (child != null && child.getId() != null) { + writeLevel(child, writer); + } + writer.writeEndElement(); + } + } + + @RequiredArgsConstructor + private static class HierarchyUrnAdapterWrapper implements Hierarchy { + + private final Hierarchy adapted; + + @Override + public String getUrn() { + return "urn:sdmx:org.sdmx.infomodel.codelist.HierarchicalCodelist=" + + adapted.getOrganizationId() + + ":" + adapted.getId() + + "(" + adapted.getVersion() + ")"; + } + + + // unsupported + @Override + public boolean deepEquals(Object o) { + throw new UnsupportedOperationException("Unexpected usage of this class"); + } + + @Override + public boolean deepEquals(Object o, Set set) { + throw new UnsupportedOperationException("Unexpected usage of this class"); + } + + // just delegate the rest of the methods to the adapted object + @Override + public boolean isExternalReference() { + return adapted.isExternalReference(); + } + + @Override + public URL getServiceUrl() { + return adapted.getServiceUrl(); + } + + @Override + public URL getStructureUrl() { + return adapted.getStructureUrl(); + } + + @Override + public Set getReferencedArtefacts() { + return adapted.getReferencedArtefacts(); + } + + @Override + public ArtefactReference getMaintainer() { + return adapted.getMaintainer(); + } + + @Override + public String getOrganizationId() { + return adapted.getOrganizationId(); + } + + @Override + public Hierarchy toStub() { + return adapted.toStub(); + } + + @Override + public Hierarchy toCompleteStub() { + return adapted.toCompleteStub(); + } + + @Override + public ArtefactReference toReference() { + return adapted.toReference(); + } + + @Override + public boolean isStub() { + return adapted.isStub(); + } + + @Override + public List getLinks() { + return adapted.getLinks(); + } + + @Override + public boolean isHasFormalLevels() { + return adapted.isHasFormalLevels(); + } + + @Override + public Level getLevel() { + return adapted.getLevel(); + } + + @Override + public List getCodes() { + return adapted.getCodes(); + } + + @Override + public Version getVersion() { + return adapted.getVersion(); + } + + @Override + public Instant getValidFrom() { + return adapted.getValidFrom(); + } + + @Override + public Instant getValidTo() { + return adapted.getValidTo(); + } + + @Override + public String getValidFromString() { + return adapted.getValidFromString(); + } + + @Override + public String getValidToString() { + return adapted.getValidToString(); + } + + @Override + public InternationalString getName() { + return adapted.getName(); + } + + @Override + public InternationalString getDescription() { + return adapted.getDescription(); + } + + @Override + public String getNameInDefaultLocale() { + return adapted.getNameInDefaultLocale(); + } + + @Override + public String getDescriptionInDefaultLocale() { + return adapted.getDescriptionInDefaultLocale(); + } + + @Override + public String getId() { + return adapted.getId(); + } + + @Override + public StructureClass getStructureClass() { + return adapted.getStructureClass(); + } + + @Override + public URI getUri() { + return adapted.getUri(); + } + + @Override + public ArtefactReference getContainer() { + return adapted.getContainer(); + } + + @Override + public List getAnnotations() { + return adapted.getAnnotations(); + } + } +} \ No newline at end of file diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ItemSchemeMapWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ItemSchemeMapWriter.java new file mode 100644 index 0000000..fe44567 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ItemSchemeMapWriter.java @@ -0,0 +1,46 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; + +import org.apache.commons.collections4.CollectionUtils; + +public interface ItemSchemeMapWriter { + + default void writeItems(XMLStreamWriter writer, List itemMaps, AnnotableWriter annotableWriter) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(itemMaps)) { + for (ItemMap itemMap : itemMaps) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.ITEM_MAP); + + writer.writeAttribute(XmlConstants.VALID_TO, XmlWriterUtils.instantToDateString(itemMap.getValidTo())); + writer.writeAttribute(XmlConstants.VALID_FROM, XmlWriterUtils.instantToDateString(itemMap.getValidFrom())); + annotableWriter.write(itemMap, writer); + + String source = itemMap.getSource(); + writeSource(writer, source, XmlConstants.STR + XmlConstants.SOURCE_VALUE); + + String target = itemMap.getTarget(); + writeTarget(writer, target, XmlConstants.STR + XmlConstants.TARGET_VALUE); + + writer.writeEndElement(); + } + } + } + + default void writeTarget(XMLStreamWriter writer, String target, String name) throws XMLStreamException { + writer.writeStartElement(name); + XmlWriterUtils.writeCharacters(target, writer); + writer.writeEndElement(); + } + + default void writeSource(XMLStreamWriter writer, String source, String name) throws XMLStreamException { + writer.writeStartElement(name); + XmlWriterUtils.writeCharacters(source, writer); + writer.writeEndElement(); + } + +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/MeasureListWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/MeasureListWriter.java new file mode 100644 index 0000000..cb6dacb --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/MeasureListWriter.java @@ -0,0 +1,73 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static java.util.stream.Collectors.joining; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Measure; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.Representation; + +import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +@AllArgsConstructor +public class MeasureListWriter { + + public static final String PRIMARY_MEASURE_URN_CLASS = "urn:sdmx:org.sdmx.infomodel.datastructure.PrimaryMeasure="; + private final AnnotableWriter annotableWriter; + private final RepresentationWriter representationWriter; + private final ReferenceWriter referenceWriter; + + public void writeMeasureList(MeasureDescriptor measureDescriptor, XMLStreamWriter writer) throws XMLStreamException { + if (measureDescriptor != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.MEASURE_LIST); + XmlWriterUtils.writeIdUriAttributes( + writer, + XmlConstants.MEASURE_DESCRIPTOR_ID, + measureDescriptor.getUri() + ); + if (measureDescriptor.getContainer() != null) { + XmlWriterUtils.writeUrn(measureDescriptor.getUrn(), writer); + } + annotableWriter.write(measureDescriptor, writer); + List components = measureDescriptor.getComponents(); + writeMeasures(writer, components); + writer.writeEndElement(); + } + } + + private void writeMeasures(XMLStreamWriter writer, List measures) throws XMLStreamException { + if (CollectionUtils.size(measures) <= 1) { + for (Measure measure : CollectionUtils.emptyIfNull(measures)) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.PRIMARY_MEASURE); + XmlWriterUtils.writeIdUriAttributes(writer, measure.getId(), measure.getUri()); + if (measure.getContainer() != null) { + final String primaryMeasureUrn = fixPrimaryMeasureUrn(measure); + XmlWriterUtils.writeUrn(primaryMeasureUrn, writer); + } + annotableWriter.write(measure, writer); + referenceWriter.writeConceptIdentity(writer, measure); + Representation localRepresentation = measure.getLocalRepresentation(); + if (localRepresentation != null) { + representationWriter.writeRepresentation(writer, localRepresentation, XmlConstants.LOCAL_REPRESENTATION); + } + writer.writeEndElement(); + } + } else { + throw new IllegalArgumentException("Only one primary measure is expected, but found: " + + measures.size() + " measures: " + + measures.stream().map(Measure::getId).collect(joining(", "))); + } + } + + private static String fixPrimaryMeasureUrn(Measure measure) { + final String measureUrn = measure.getUrn(); + final String measureAgencyIdVersionId = StringUtils.substringAfter(measureUrn, "="); + return PRIMARY_MEASURE_URN_CLASS + measureAgencyIdVersionId; + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/MemberSelectionWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/MemberSelectionWriter.java new file mode 100644 index 0000000..76c07c7 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/MemberSelectionWriter.java @@ -0,0 +1,118 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static com.epam.jsdmx.xml21.structure.writer.XmlWriterUtils.writeCharacters; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.AfterPeriod; +import com.epam.jsdmx.infomodel.sdmx30.BeforePeriod; +import com.epam.jsdmx.infomodel.sdmx30.LocalisedMemberValue; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.MemberValue; +import com.epam.jsdmx.infomodel.sdmx30.MemberValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.RangePeriod; +import com.epam.jsdmx.infomodel.sdmx30.RangePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.SelectionValue; +import com.epam.jsdmx.infomodel.sdmx30.TimeRangePeriod; +import com.epam.jsdmx.infomodel.sdmx30.TimeRangeValue; + +import org.apache.commons.collections4.CollectionUtils; + +public class MemberSelectionWriter { + + public void writeMemberSelections(XMLStreamWriter writer, List memberSelections) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(memberSelections)) { + for (MemberSelection memberSelection : memberSelections) { + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.ATTRIBUTE); + + boolean includedMember = memberSelection.isIncluded(); + writer.writeAttribute(XmlConstants.INCLUDE, String.valueOf(includedMember)); + + String componentId = memberSelection.getComponentId(); + writer.writeAttribute(XmlConstants.ID, componentId); + + List selectionValues = memberSelection.getSelectionValues(); + writeSelectionValues(writer, selectionValues); + + writer.writeEndElement(); + } + } + } + + public void writeSelectionValues(XMLStreamWriter writer, List selectionValues) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(selectionValues)) { + for (SelectionValue selectionValue : selectionValues) { + if (selectionValue instanceof MemberValue) { + writeMemberValue(writer, (MemberValueImpl) selectionValue); + } else if (selectionValue instanceof LocalisedMemberValue) { + writeLocalisedMemberValue(writer, (LocalisedMemberValue) selectionValue); + } else if (selectionValue instanceof TimeRangeValue) { + writeTimeRange(writer, selectionValue); + } + } + } + } + + private void writeTimeRange(XMLStreamWriter writer, SelectionValue selectionValue) throws XMLStreamException { + if (selectionValue != null) { + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.TIME_RANGE); + + if (selectionValue instanceof BeforePeriod) { + BeforePeriod beforePeriod = (BeforePeriod) selectionValue; + writeTimeRangePeriod(writer, beforePeriod, XmlConstants.BEFORE_PERIOD); + } else if (selectionValue instanceof AfterPeriod) { + AfterPeriod afterPeriod = (AfterPeriod) selectionValue; + writeTimeRangePeriod(writer, afterPeriod, XmlConstants.AFTER_PERIOD); + } else if (selectionValue instanceof RangePeriod) { + RangePeriodImpl rangePeriod = (RangePeriodImpl) selectionValue; + writeRangePeriod(rangePeriod.getStartPeriod(), writer, XmlConstants.START_PERIOD); + writeRangePeriod(rangePeriod.getEndPeriod(), writer, XmlConstants.END_PERIOD); + } + + writer.writeEndElement(); + } + } + + private void writeRangePeriod(TimeRangePeriod rangePeriod, XMLStreamWriter writer, String periodName) throws XMLStreamException { + if (rangePeriod != null) { + writer.writeStartElement(XmlConstants.COMMON + periodName); + + writer.writeAttribute(XmlConstants.IS_INCLUSIVE, String.valueOf(rangePeriod.isInclusive())); + writeCharacters(rangePeriod.getPeriod(), writer); + + writer.writeEndElement(); + } + } + + private void writeMemberValue(XMLStreamWriter writer, MemberValueImpl memberVal) throws XMLStreamException { + if (memberVal != null) { + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.VALUE); + writeCharacters(memberVal.getValue(), writer); + writer.writeEndElement(); + } + } + + private void writeLocalisedMemberValue(XMLStreamWriter writer, LocalisedMemberValue localisedMemberValue) throws XMLStreamException { + if (localisedMemberValue != null) { + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.VALUE); + writeCharacters(localisedMemberValue.getValue(), writer); + writer.writeEndElement(); + } + } + + private void writeTimeRangePeriod(XMLStreamWriter writer, + TimeRangePeriod selectionValue, + String timeRangeName) throws XMLStreamException { + writer.writeStartElement(XmlConstants.COMMON + timeRangeName); + + boolean inclusive = selectionValue.isInclusive(); + writer.writeAttribute(XmlConstants.IS_INCLUSIVE, String.valueOf(inclusive)); + + writeCharacters(selectionValue.getPeriod(), writer); + + writer.writeEndElement(); + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/MetadataConstraintWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/MetadataConstraintWriter.java new file mode 100644 index 0000000..0f0cdf2 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/MetadataConstraintWriter.java @@ -0,0 +1,38 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.MetadataTargetRegion; + +import org.apache.commons.collections4.CollectionUtils; + +public class MetadataConstraintWriter { + + private final MemberSelectionWriter memberSelectionWriter; + + public MetadataConstraintWriter(MemberSelectionWriter memberSelectionWriter) { + this.memberSelectionWriter = memberSelectionWriter; + } + + public void writeMetadataTargetRegions(XMLStreamWriter writer, List metadataTargetRegions) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(metadataTargetRegions)) { + for (MetadataTargetRegion metadataTargetRegion : metadataTargetRegions) { + if (metadataTargetRegion != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.METADATA_TARGET_REGION); + boolean included = metadataTargetRegion.isIncluded(); + writer.writeAttribute(XmlConstants.INCLUDE, String.valueOf(included)); + writer.writeAttribute(XmlConstants.REPORT, "skipped"); + writer.writeAttribute(XmlConstants.METADATA_TARGET, "skipped"); + List memberSelections = metadataTargetRegion.getMemberSelections(); + memberSelectionWriter.writeMemberSelections(writer, memberSelections); + + writer.writeEndElement(); + } + } + } + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/NameableWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/NameableWriter.java new file mode 100644 index 0000000..8d42e10 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/NameableWriter.java @@ -0,0 +1,19 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static com.epam.jsdmx.xml21.structure.writer.XmlWriterUtils.writeInternationalString; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.NameableArtefact; + +public class NameableWriter { + + public void write(NameableArtefact artefact, XMLStreamWriter writer) throws XMLStreamException { + InternationalString name = artefact.getName(); + writeInternationalString(name, writer, XmlConstants.COMMON + XmlConstants.COM_NAME); + InternationalString description = artefact.getDescription(); + writeInternationalString(description, writer, XmlConstants.COMMON + XmlConstants.COM_DESCRIPTION); + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/OrganisationSchemeWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/OrganisationSchemeWriter.java new file mode 100644 index 0000000..70b8fec --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/OrganisationSchemeWriter.java @@ -0,0 +1,124 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl.AGENCY_SCHEME; +import static com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl.DATA_CONSUMER_SCHEME; +import static com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl.DATA_PROVIDER_SCHEME; + +import java.util.HashSet; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.AgencyScheme; +import com.epam.jsdmx.infomodel.sdmx30.AgencySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerScheme; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderScheme; +import com.epam.jsdmx.infomodel.sdmx30.Organisation; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationScheme; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; +import com.epam.jsdmx.infomodel.sdmx30.Version; + +public class OrganisationSchemeWriter extends XmlWriter>> { + + private final OrganisationWriter organisationWriter; + + public OrganisationSchemeWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + OrganisationWriter organisationWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter); + this.organisationWriter = organisationWriter; + } + + @Override + protected void writeAttributes(OrganisationScheme scheme, XMLStreamWriter writer) throws XMLStreamException { + if (scheme instanceof AgencyScheme) { + var agencyScheme = (AgencyScheme) scheme; + AgencySchemeImpl agencySchemeImpl = (AgencySchemeImpl) agencyScheme; + agencySchemeImpl.setVersion(Version.createFromString(XmlConstants.DEFAULT_VERSION)); + commonAttributesWriter.writeAttributes( + "AGENCIES", + "SDMX", + agencyScheme.getUri(), + agencySchemeImpl.getUrn(), + null, + agencyScheme.isExternalReference(), + agencyScheme.getServiceUrl(), + agencyScheme.getStructureUrl(), + agencyScheme.getValidToString(), + agencyScheme.getValidFromString(), + writer + ); + } else if (scheme instanceof DataProviderScheme) { + var dataProviderScheme = (DataProviderScheme) scheme; + commonAttributesWriter.writeAttributes( + "DATA_PROVIDERS", + "SDMX", + dataProviderScheme.getUri(), + dataProviderScheme.getUrn(), + null, + dataProviderScheme.isExternalReference(), + dataProviderScheme.getServiceUrl(), + dataProviderScheme.getStructureUrl(), + dataProviderScheme.getValidToString(), + dataProviderScheme.getValidFromString(), + writer + ); + } else if (scheme instanceof DataConsumerScheme) { + var dataConsumerScheme = (DataConsumerScheme) scheme; + commonAttributesWriter.writeAttributes( + "DATA_CONSUMERS", + "SDMX", + dataConsumerScheme.getUri(), + dataConsumerScheme.getUrn(), + null, + dataConsumerScheme.isExternalReference(), + dataConsumerScheme.getServiceUrl(), + dataConsumerScheme.getStructureUrl(), + dataConsumerScheme.getValidToString(), + dataConsumerScheme.getValidFromString(), + writer + ); + } + } + + @Override + protected void writeCustomAttributeElements(OrganisationScheme orgScheme, XMLStreamWriter writer) throws XMLStreamException { + String orgName = getOrgName(orgScheme); + organisationWriter.writeOrganisation(orgScheme.getItems(), writer, orgName); + } + + private String getOrgName(OrganisationScheme orgScheme) { + StructureClass structureClass = orgScheme.getStructureClass(); + if (structureClass == AGENCY_SCHEME) { + return XmlConstants.AGENCY; + } else if (structureClass == DATA_PROVIDER_SCHEME) { + return XmlConstants.DATA_PROVIDER; + } else if (structureClass == DATA_CONSUMER_SCHEME) { + return XmlConstants.DATA_CONSUMER; + } + throw new IllegalArgumentException("Unknown structure class: " + structureClass); + } + + @Override + protected String getName(OrganisationScheme scheme) { + return scheme.getStructureClass().getSimpleName(); + } + + @Override + protected String getNamePlural() { + return XmlConstants.ORGANISATION_SCHEMES; + } + + @Override + protected Set> extractArtefacts(Artefacts artefacts) { + var allOrgSchemes = new HashSet>(); + allOrgSchemes.addAll(artefacts.getAgencySchemes()); + allOrgSchemes.addAll(artefacts.getDataProviderSchemes()); + allOrgSchemes.addAll(artefacts.getDataConsumerSchemes()); + return allOrgSchemes; + } + +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/OrganisationWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/OrganisationWriter.java new file mode 100644 index 0000000..12694e4 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/OrganisationWriter.java @@ -0,0 +1,66 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Contact; +import com.epam.jsdmx.infomodel.sdmx30.Organisation; + +import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; + +@AllArgsConstructor +public class OrganisationWriter { + + private final ContactWriter contactWriter; + private final AnnotableWriter annotableWriter; + private final NameableWriter nameableWriter; + + > void writeOrganisation(List organisationItems, + XMLStreamWriter writer, + String name) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(organisationItems)) { + Map parentIdWithHierarchy = new HashMap<>(); + for (T organisat : organisationItems) { + List> children = organisat.getHierarchy(); + if (CollectionUtils.isNotEmpty(children)) { + for (Organisation child : children) { + parentIdWithHierarchy.put(child.getId(), organisat.getId()); + } + } + } + for (T organisation : organisationItems) { + writeOrganisation(writer, name, parentIdWithHierarchy, organisation); + } + } + } + + private > void writeOrganisation(XMLStreamWriter writer, String name, + Map parentIdWithHierarchy, T organisation) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STR + name); + XmlWriterUtils.writeIdUriAttributes(writer, organisation.getId(), organisation.getUri()); + + if (organisation.getContainer() != null) { + XmlWriterUtils.writeUrn(organisation.getUrn(), writer); + } + + annotableWriter.write(organisation, writer); + nameableWriter.write(organisation, writer); + + List contacts = organisation.getContacts(); + contactWriter.writeContacts(contacts, writer); + + String organisationId = organisation.getId(); + if (parentIdWithHierarchy.containsKey(organisation.getId())) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.STRUCTURE_PARENT); + writer.writeCharacters(parentIdWithHierarchy.get(organisationId)); + writer.writeEndElement(); + } + + writer.writeEndElement(); + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ReferenceWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ReferenceWriter.java new file mode 100644 index 0000000..d86e7ff --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ReferenceWriter.java @@ -0,0 +1,201 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Component; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; +import com.epam.jsdmx.serializer.sdmx21.ReferenceResolver; + +import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; + +@RequiredArgsConstructor +public class ReferenceWriter { + + private static final String AGENCY_ID = "agencyID"; + private static final String ID = "id"; + private static final String PACKAGE = "package"; + private static final String CLASS = "class"; + + private static final String CODELIST_PCKG = "codelist"; + private static final String CATEGORY_SCHEME_PCKG = "categoryscheme"; + private static final String CONCEPT_SCHEME_PCKG = "conceptscheme"; + private static final String DATASTRUCTURE_PCKG = "datastructure"; + private static final String METADATASTRUCTURE_PCKG = "metadatastructure"; + private static final String PROVISION_AGREEMENT_PCKG = "registry"; + + private final ReferenceResolver referenceResolver; + private final ReferenceAdapter referenceAdapter; + + public void writeUrn(XMLStreamWriter writer, String urn) throws XMLStreamException { + XmlWriterUtils.writeUrn(referenceAdapter.adaptUrn(urn), writer); + } + + public void writeUrnAttribute(XMLStreamWriter writer, String urn) throws XMLStreamException { + writer.writeAttribute(XmlConstants.URN, referenceAdapter.adaptUrn(urn)); + } + + public void writeConceptIdentity(XMLStreamWriter writer, Component component) throws XMLStreamException { + ArtefactReference conceptIdentity = component.getConceptIdentity(); + if (conceptIdentity != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.CONCEPT_IDENTITY); + writeConceptReference(writer, conceptIdentity); + writer.writeEndElement(); + } + } + + public void writeConceptReference(XMLStreamWriter writer, ArtefactReference conceptIdentity) throws XMLStreamException { + writeItemReference(writer, conceptIdentity, CONCEPT_SCHEME_PCKG, "Concept"); + } + + public void writeCodeReference(XMLStreamWriter writer, ArtefactReference concept) throws XMLStreamException { + writeItemReference(writer, concept, CODELIST_PCKG, "Code"); + } + + public void writeCategoryReference(XMLStreamWriter writer, ArtefactReference category) throws XMLStreamException { + writeItemReference(writer, category, CATEGORY_SCHEME_PCKG, "Category"); + } + + + public void writeItemReference(XMLStreamWriter writer, ArtefactReference itemRef, String packg, String clss) throws XMLStreamException { + final ArtefactReference resolved = referenceResolver.resolve(itemRef); + + writer.writeEmptyElement(XmlConstants.REF); + writer.writeAttribute("maintainableParentID", itemRef.getId()); + writer.writeAttribute("maintainableParentVersion", resolved.getVersionString()); + writer.writeAttribute(AGENCY_ID, itemRef.getOrganisationId()); + writer.writeAttribute(ID, itemRef.getItemId()); + writer.writeAttribute(PACKAGE, packg); + writer.writeAttribute(CLASS, clss); + } + + public void writeCodelistReference(XMLStreamWriter writer, ArtefactReference ref) throws XMLStreamException { + writeMaintainableReference(writer, ref, CODELIST_PCKG, "Codelist"); + } + + public void writeDataStructureReference(XMLStreamWriter writer, ArtefactReference ref) throws XMLStreamException { + writeMaintainableReference(writer, ref, DATASTRUCTURE_PCKG, "DataStructure"); + } + + public void writeMetaDataStructureReference(XMLStreamWriter writer, ArtefactReference ref) throws XMLStreamException { + writeMaintainableReference(writer, ref, METADATASTRUCTURE_PCKG, "MetadataStructure"); + } + + public void writeDataflowReference(XMLStreamWriter writer, ArtefactReference ref) throws XMLStreamException { + writeMaintainableReference(writer, ref, DATASTRUCTURE_PCKG, "Dataflow"); + } + + public void writeMetaDataflowReference(XMLStreamWriter writer, ArtefactReference ref) throws XMLStreamException { + writeMaintainableReference(writer, ref, METADATASTRUCTURE_PCKG, "Metadataflow"); + } + + public void writeProvisionAgreementReference(XMLStreamWriter writer, ArtefactReference ref) throws XMLStreamException { + writeMaintainableReference(writer, ref, PROVISION_AGREEMENT_PCKG, "ProvisionAgreement"); + } + + public void writeMetaProvisionAgreementReference(XMLStreamWriter writer, ArtefactReference ref) throws XMLStreamException { + writeMaintainableReference(writer, ref, PROVISION_AGREEMENT_PCKG, "MetadataProvisionAgreement"); + } + + public void writeMetadataSetReference(XMLStreamWriter writer, ArtefactReference ref) throws XMLStreamException { + writeMaintainableReference(writer, ref, METADATASTRUCTURE_PCKG, "MetadataSet"); + } + + public void writeDimensionReference(XMLStreamWriter writer, String groupDimensionName) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STR + XmlConstants.DIMENSION_REFERENCE); + writer.writeEmptyElement(XmlConstants.REF); + writer.writeAttribute(XmlConstants.ID, groupDimensionName); + writer.writeEndElement(); + } + + public void writeObjectReference(XMLStreamWriter writer, ArtefactReference artefact) throws XMLStreamException { + final ArtefactReference resolved = referenceResolver.resolve(artefact); + final String packg = getPackageFor(resolved); + final String klass = getClassName(resolved); + if (artefact.isItemReference()) { + writeItemReference(writer, artefact, packg, klass); + } else { + writeMaintainableReference(writer, artefact, packg, klass); + } + } + + private String getClassName(ArtefactReference resolved) { + final StructureClass structureClass = getStructureClass(resolved); + if (StructureClassImpl.HIERARCHY.equals(structureClass)) { + return "HierarchicalCodelist"; + } + return structureClass.getSimpleName(); + } + + private StructureClass getStructureClass(ArtefactReference resolved) { + return referenceAdapter.adaptType(resolved.getStructureClass()); + } + + private String getPackageFor(ArtefactReference ref) { + final StructureClass structureClass = getStructureClass(ref); + //dataflow + //data structure + if (StructureClassImpl.DATAFLOW.equals(structureClass) + || StructureClassImpl.DATA_STRUCTURE.equals(structureClass)) { + return "datastructure"; + } + //category scheme + //categorisation + if (StructureClassImpl.CATEGORY_SCHEME.equals(structureClass) + || StructureClassImpl.CATEGORY.equals(structureClass) + || StructureClassImpl.CATEGORISATION.equals(structureClass)) { + return "categoryscheme"; + } + //codelist + //hierarchical codelist + if (StructureClassImpl.CODELIST.equals(structureClass) + || StructureClassImpl.CODE.equals(structureClass) + || StructureClassImpl.HIERARCHY.equals(structureClass)) { + return "codelist"; + } + //concept scheme + if (StructureClassImpl.CONCEPT_SCHEME.equals(structureClass) + || StructureClassImpl.CONCEPT.equals(structureClass)) { + return "conceptscheme"; + } + return "base"; + } + + private void writeMaintainableReference(XMLStreamWriter writer, ArtefactReference ref, String packg, String clss) throws XMLStreamException { + final ArtefactReference resolved = referenceResolver.resolve(ref); + + writer.writeEmptyElement(XmlConstants.REF); + writer.writeAttribute(AGENCY_ID, ref.getOrganisationId()); + writer.writeAttribute(ID, ref.getId()); + writer.writeAttribute("version", resolved.getVersionString()); + writer.writeAttribute(PACKAGE, packg); + writer.writeAttribute(CLASS, clss); + } + + /** + * with id only + **/ + public void writeLocalReference(XMLStreamWriter writer, String id) throws XMLStreamException { + writer.writeEmptyElement(XmlConstants.REF); + XmlWriterUtils.writeMandatoryAttribute(id, writer, XmlConstants.ID); + } + + public void writeConceptRoles(XMLStreamWriter writer, List conceptRoles) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(conceptRoles)) { + for (ArtefactReference concept : conceptRoles) { + if (concept != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.CONCEPT_ROLE); + writeConceptReference(writer, concept); + writer.writeEndElement(); + } + } + } + } + +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ReleaseCalenderWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ReleaseCalenderWriter.java new file mode 100644 index 0000000..a93f69f --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/ReleaseCalenderWriter.java @@ -0,0 +1,36 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendar; + +public class ReleaseCalenderWriter { + + public void writeReleaseCalendar(XMLStreamWriter writer, ReleaseCalendar releaseCalendar) throws XMLStreamException { + if (releaseCalendar != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.RELEASE_CALENDAR); + + String periodicity = releaseCalendar.getPeriodicity(); + writeReleaseCalendarComponent(writer, periodicity, XmlConstants.PERIODICITY); + + String offset = releaseCalendar.getOffset(); + writeReleaseCalendarComponent(writer, offset, XmlConstants.OFFSET); + + String tolerance = releaseCalendar.getTolerance(); + writeReleaseCalendarComponent(writer, tolerance, XmlConstants.TOLERANCE); + + writer.writeEndElement(); + } + } + + private void writeReleaseCalendarComponent(XMLStreamWriter writer, + String component, + String componentName) throws XMLStreamException { + if (component != null) { + writer.writeStartElement(XmlConstants.STR + componentName); + writer.writeCharacters(component); + writer.writeEndElement(); + } + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/RepresentationWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/RepresentationWriter.java new file mode 100644 index 0000000..9a97e1f --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/RepresentationWriter.java @@ -0,0 +1,172 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Facet; +import com.epam.jsdmx.infomodel.sdmx30.FacetType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.infomodel.sdmx30.TextFormatImpl; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class RepresentationWriter { + + private final ReferenceWriter referenceWriter; + + public void writeRepresentation(XMLStreamWriter writer, Representation representation, String representationName) throws XMLStreamException { + if (representation != null) { + writer.writeStartElement(XmlConstants.STR + representationName); + boolean enumerated = representation.isEnumerated(); + if (enumerated) { + writeEnumerated(writer, representation); + } else { + writeTextFormat(writer, representation); + } + writer.writeEndElement(); + } + } + + private void writeTextFormat(XMLStreamWriter writer, Representation coreRepresentation) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STR + XmlConstants.TEXT_FORMAT); + Set facets = coreRepresentation.nonEnumerated(); + if (!facets.isEmpty()) { + TextFormatImpl textFormat = new TextFormatImpl(facets); + writeTextFormatAttribute(writer, textFormat); + } + writer.writeEndElement(); + } + + private void writeEnumerated(XMLStreamWriter writer, Representation coreRepresentation) throws XMLStreamException { + ArtefactReference artefactReference = coreRepresentation.enumerated(); + if (artefactReference != null) { + writer.writeStartElement(XmlConstants.STR + XmlConstants.ENUMERATION); + ArtefactReference maintainableArtefactReference = artefactReference.getMaintainableArtefactReference(); + if (maintainableArtefactReference != null) { + referenceWriter.writeCodelistReference(writer, maintainableArtefactReference); + } + writer.writeEndElement(); + + } + } + + private void writeTextFormatAttribute(XMLStreamWriter writer, TextFormatImpl textFormat) throws XMLStreamException { + + if (textFormat.hasValueType()) { + Optional valueType = textFormat.getValueType(); + writer.writeAttribute(XmlConstants.TEXT_TYPE, valueType.get().value()); + } + + if (textFormat.hasDecimals()) { + Optional decimals = textFormat.getDecimals(); + if (decimals.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.DECIMALS.name()), String.valueOf(decimals.get())); + } + return; + } + + if (textFormat.hasEndTime()) { + Optional endTime = textFormat.getEndTime(); + if (endTime.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.END_TIME.name()), String.valueOf(endTime.get())); + } + return; + } + + if (textFormat.hasInterval()) { + Optional interval = textFormat.getInterval(); + if (interval.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.INTERVAL.name()), String.valueOf(textFormat.getInterval())); + } + return; + } + + if (textFormat.hasEndValue()) { + Optional endValue = textFormat.getEndValue(); + if (endValue.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.END_VALUE.name()), String.valueOf(endValue)); + } + return; + } + + if (textFormat.hasIsSequence()) { + Optional isSequence = textFormat.getIsSequence(); + if (isSequence.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.IS_SEQUENCE.name()), String.valueOf(isSequence)); + } + return; + } + + if (textFormat.hasMaxValue()) { + Optional maxValue = textFormat.getMaxValue(); + if (maxValue.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.MAX_VALUE.name()), String.valueOf(maxValue)); + } + return; + } + + if (textFormat.hasMinValue()) { + Optional minValue = textFormat.getMinValue(); + if (minValue.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.MIN_VALUE.name()), String.valueOf(minValue)); + } + return; + } + + if (textFormat.hasMaxLength()) { + Optional maxLength = textFormat.getMaxLength(); + if (maxLength.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.MAX_LENGTH.name()), String.valueOf(maxLength)); + } + return; + } + + if (textFormat.hasMinLength()) { + Optional minLength = textFormat.getMinLength(); + if (minLength.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.MIN_LENGTH.name()), String.valueOf(minLength)); + } + return; + } + + if (textFormat.hasStartTime()) { + Optional startTime = textFormat.getStartTime(); + if (startTime.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.START_TIME.name()), String.valueOf(startTime)); + } + return; + } + + if (textFormat.hasStartValue()) { + Optional startValue = textFormat.getStartValue(); + if (startValue.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.START_VALUE.name()), String.valueOf(startValue)); + } + return; + } + + if (textFormat.hasPattern()) { + Optional pattern = textFormat.getPattern(); + if (pattern.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.PATTERN.name()), String.valueOf(pattern)); + } + return; + } + + if (textFormat.hasTimeInterval()) { + Optional timeInterval = textFormat.getTimeInterval(); + if (timeInterval.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.TIME_INTERVAL.name()), String.valueOf(timeInterval)); + } + } + } +} \ No newline at end of file diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/Xml21StructureWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/Xml21StructureWriter.java new file mode 100644 index 0000000..a0fbcfc --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/Xml21StructureWriter.java @@ -0,0 +1,92 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.serializer.sdmx30.structure.StructureWriter; + +import com.sun.xml.txw2.output.IndentingXMLStreamWriter; +import lombok.SneakyThrows; + +/** + * Streaming serialization for xml 2.1 + */ +public class Xml21StructureWriter implements StructureWriter { + private final XMLStreamWriter writer; + protected final HeaderWriter headerWriter; + + private final List> writerList; + + @SneakyThrows + public Xml21StructureWriter(OutputStream outputStream, + List> writerList, + HeaderWriter headerWriter, + boolean isPretty) { + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance() + .createXMLStreamWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); + this.writer = isPretty ? new IndentingXMLStreamWriter(xmlStreamWriter) : xmlStreamWriter; + this.writerList = List.copyOf(writerList); + this.headerWriter = headerWriter; + } + + @Override + @SneakyThrows + public void write(Artefacts artefacts) { + try { + writer.writeStartDocument(); + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.MES_STRUCTURE); + writeNameSpaces(); + writer.writeAttribute("xsi:schemaLocation", "http://www.sdmx.org/resources/sdmxml/schemas/v2_1/message ../../schemas/SDMXMessage.xsd"); + + headerWriter.writeDefaultHeader(writer); + + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.MES_STRUCTURES); + + writerList.forEach(xmlWriter -> { + try { + Set maintainableArtefacts = xmlWriter.extractArtefacts(artefacts); + if (!maintainableArtefacts.isEmpty()) { + writer.writeStartElement(XmlConstants.STR + xmlWriter.getNamePlural()); + maintainableArtefacts.forEach(artefact -> { + try { + if (artefact.getVersion().isStable()) { + xmlWriter.write(artefact, writer); + } + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + }); + writer.writeEndElement(); + } + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + }); + + writer.writeEndElement(); + + writer.writeEndElement(); + writer.writeEndDocument(); + writer.close(); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + + private void writeNameSpaces() throws XMLStreamException { + writer.writeNamespace("mes", XmlConstants.SCHEMAS_V_2_1_MESSAGE); + writer.writeNamespace("str", XmlConstants.SCHEMAS_V_2_1_STRUCTURE); + writer.writeNamespace("com", XmlConstants.SCHEMAS_V_2_1_COMMON); + writer.writeNamespace("xsi", XmlConstants.XMLSCHEMA_INSTANCE); + writer.writeNamespace("xml", XmlConstants.XML_1998_NAMESPACE); + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/Xml21WriterFactory.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/Xml21WriterFactory.java new file mode 100644 index 0000000..3e4bf37 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/Xml21WriterFactory.java @@ -0,0 +1,155 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; +import com.epam.jsdmx.serializer.common.TimeDimensionLocalRepresentationAdapter; +import com.epam.jsdmx.serializer.sdmx21.DataStructure30To21ComponentAdapter; +import com.epam.jsdmx.serializer.sdmx21.ReferenceResolver; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultHeaderProvider; + +public class Xml21WriterFactory { + + private final DataStructure30To21ComponentAdapter dsdAdapter; + private final TimeDimensionLocalRepresentationAdapter dsdLocalRepresentationAdapter; + private final ReferenceResolver referenceResolver; + private final ReferenceAdapter referenceAdapter; + + public Xml21WriterFactory(DataStructure30To21ComponentAdapter dsdAdapter, + TimeDimensionLocalRepresentationAdapter dsdLocalRepresentationAdapter, + ReferenceResolver resolver, + ReferenceAdapter referenceAdapter) { + this.dsdAdapter = dsdAdapter; + this.dsdLocalRepresentationAdapter = dsdLocalRepresentationAdapter; + this.referenceResolver = resolver; + this.referenceAdapter = referenceAdapter; + } + + public Xml21StructureWriter newInstance(OutputStream outputStream, boolean isPretty) { + HeaderWriter headerWriter = new HeaderWriter(new DefaultHeaderProvider()); + return new Xml21StructureWriter( + outputStream, + writers(), + headerWriter, + isPretty + ); + } + + public Xml21StructureWriter newInstance(OutputStream outputStream, + boolean isPretty, + Map> customStructureWriters) { + HeaderWriter headerWriter = new HeaderWriter(new DefaultHeaderProvider()); + var defaultWriters = writers(); + List> writers = new ArrayList<>(); + + for (var writer : defaultWriters) { + writer.getWritableArtefactStructureClass() + .filter(customStructureWriters::containsKey) + .map(customStructureWriters::get) + .ifPresentOrElse(writers::add, () -> writers.add(writer)); + } + + return new Xml21StructureWriter( + outputStream, + writers, + headerWriter, + isPretty + ); + } + private List> writers() { + + final var annotableWriter = new AnnotableWriter(); + final var nameableWriter = new NameableWriter(); + final var contactWriter = new ContactWriter(); + + final var referenceWriter = new ReferenceWriter(referenceResolver, referenceAdapter); + final var representationWriter = new RepresentationWriter(referenceWriter); + + final var attributeListWriter = new AttributeListWriter(annotableWriter, representationWriter, referenceWriter); + final var dimensionListWriter = new DimensionListWriter(annotableWriter, representationWriter, referenceWriter); + final var measureListWriter = new MeasureListWriter(annotableWriter, representationWriter, referenceWriter); + final var groupDimensionListWriter = new GroupDimensionListWriter(annotableWriter, referenceWriter); + + final var commonAttributesWriter = new CommonAttributesWriter(referenceWriter); + + final var organisationWriter = new OrganisationWriter(contactWriter, annotableWriter, nameableWriter); + + final var codeWriter = new CodeWriterImpl(referenceWriter, nameableWriter, annotableWriter); + + final var memberSelectionWriter = new MemberSelectionWriter(); + final var releaseCalenderWriter = new ReleaseCalenderWriter(); + final var dataKeySetsWriter = new DataKeySetsWriter(annotableWriter, memberSelectionWriter); + final var cubeRegionWriter = new CubeRegionWriter(annotableWriter, memberSelectionWriter); + final var metadataConstraintWriter = new MetadataConstraintWriter(memberSelectionWriter); + + return List.of( + new OrganisationSchemeWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + organisationWriter + ), + new DataflowWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + referenceWriter + ), + new CategorySchemeWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter + ), + new CategorisationWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + referenceWriter + ), + new CodelistWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + codeWriter + ), + new HierarchicalCodelistWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + referenceWriter + ), + new ConceptSchemeWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + representationWriter + ), + new DataStructureDefinitionWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + attributeListWriter, + dimensionListWriter, + measureListWriter, + groupDimensionListWriter, + dsdAdapter, + dsdLocalRepresentationAdapter + ), + new ContentConstraintWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + referenceWriter, + releaseCalenderWriter, + dataKeySetsWriter, + cubeRegionWriter, + metadataConstraintWriter + ) + ); + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/XmlConstants.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/XmlConstants.java new file mode 100644 index 0000000..fd9c8b5 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/XmlConstants.java @@ -0,0 +1,355 @@ +package com.epam.jsdmx.xml21.structure.writer; + + +import com.epam.jsdmx.infomodel.sdmx30.CascadeValue; +import com.epam.jsdmx.infomodel.sdmx30.ConstraintRoleType; +import com.epam.jsdmx.infomodel.sdmx30.EpochPeriodType; +import com.epam.jsdmx.infomodel.sdmx30.FacetType; +import com.epam.jsdmx.infomodel.sdmx30.ResolvePeriod; + +import org.apache.commons.collections4.BidiMap; +import org.apache.commons.collections4.bidimap.DualHashBidiMap; + +public final class XmlConstants { + + public static final String SCHEMAS_V_2_1_MESSAGE = "http://www.sdmx.org/resources/sdmxml/schemas/v2_1/message"; + public static final String SCHEMAS_V_2_1_STRUCTURE = "http://www.sdmx.org/resources/sdmxml/schemas/v2_1/structure"; + public static final String SCHEMAS_V_2_1_COMMON = "http://www.sdmx.org/resources/sdmxml/schemas/v2_1/common"; + public static final String XMLSCHEMA_INSTANCE = "http://www.w3.org/2001/XMLSchema-instance"; + public static final String XML_1998_NAMESPACE = "http://www.w3.org/XML/1998/namespace"; + + public static final String COMMON = "com:"; + public static final String STR = "str:"; + public static final String MESSAGE = "mes:"; + + public static final String PREFIX = "prefix"; + public static final String REF = "Ref"; + public static final String HEADER = "Header"; + public static final String MES_ID = "ID"; + public static final String MES_TEST = "Test"; + public static final String PREPARED = "Prepared"; + public static final String SENDER = "Sender"; + public static final String RECEIVER = "Receiver"; + + public static final String MES_STRUCTURES = "Structures"; + public static final String HIERARCHICAL_CODELISTS = "HierarchicalCodelists"; + public static final String CODELISTS = "Codelists"; + public static final String CONCEPT_SCHEMES = "Concepts"; + public static final String DATA_STRUCTURES = "DataStructures"; + public static final String DATAFLOWS = "Dataflows"; + public static final String METADATA_STRUCTURES = "MetadataStructures"; + public static final String METADATA_FLOWS = "Metadataflows"; + public static final String REPRESENTATION_MAPS = "RepresentationMaps"; + public static final String STRUCTURE_MAPS = "StructureMaps"; + public static final String CATEGORISATIONS = "Categorisations"; + public static final String CATEGORY_SCHEMES = "CategorySchemes"; + public static final String ORGANISATION_SCHEMES = "OrganisationSchemes"; + public static final String CATEGORY_SCHEME_MAPS = "CategorySchemeMaps"; + public static final String CONCEPT_SCHEME_MAPS = "ConceptSchemeMaps"; + public static final String DATA_CONSTRAINTS = "DataConstraints"; + public static final String DATA_CONSUMER_SCHEMES = "DataConsumerSchemes"; + public static final String DATA_PROVIDER_SCHEMES = "DataProviderSchemes"; + public static final String METADATA_PROVIDER_SCHEMES = "MetadataProviderSchemes"; + public static final String HIERARCHY_ASSOCIATIONS = "HierarchyAssociations"; + public static final String METADATA_CONSTRAINTS = "MetadataConstraints"; + public static final String METADATA_PROVISION_AGREEMENTS = "MetadataProvisionAgreements"; + public static final String ORGANISATION_SCHEME_MAPS = "OrganisationSchemeMaps"; + public static final String PROCESSES = "Processes"; + public static final String PROVISION_AGREEMENTS = "ProvisionAgreements"; + public static final String REPORTING_TAXONOMIES = "ReportingTaxonomies"; + public static final String REPORTING_TAXONOMY_MAPS = "ReportingTaxonomyMaps"; + public static final String VALUE_LISTS = "ValueLists"; + public static final String GEO_CODELISTS = "GeographicCodelists"; + public static final String GEOGRID_CODELISTS = "GeoGridCodelists"; + + public static final String MES_STRUCTURE = "Structure"; + public static final String CODELIST = "Codelist"; + public static final String HIERARCHAL_CODELIST = "HierarchicalCodelist"; + public static final String CONCEPT_SCHEME = "ConceptScheme"; + public static final String DATA_STRUCTURE = "DataStructure"; + public static final String DATAFLOW = "Dataflow"; + public static final String METADATA_FLOW = "Metadataflow"; + public static final String REPRESENTATION_MAP = "RepresentationMap"; + public static final String STRUCTURE_MAP = "StructureMap"; + public static final String CATEGORISATION = "Categorisation"; + public static final String CATEGORY_SCHEME = "CategoryScheme"; + public static final String AGENCY_SCHEME = "AgencyScheme"; + public static final String CATEGORY_SCHEME_MAP = "CategorySchemeMap"; + public static final String CONCEPT_SCHEME_MAP = "ConceptSchemeMap"; + public static final String DATA_CONSTRAINT = "DataConstraint"; + public static final String CONSTRAINTS = "Constraints"; + public static final String CONTENT_CONSTRAINT = "ContentConstraint"; + public static final String DATA_CONSUMER_SCHEME = "DataConsumerScheme"; + public static final String DATA_PROVIDER_SCHEME = "DataProviderScheme"; + public static final String METADATA_PROVIDER_SCHEME = "MetadataProviderScheme"; + public static final String HIERARCHY_ASSOCIATION = "HierarchyAssociation"; + public static final String METADATA_CONSTRAINT = "MetadataConstraint"; + public static final String ORGANISATION_SCHEME_MAP = "OrganisationSchemeMap"; + public static final String PROCESS = "Process"; + public static final String PROVISION_AGREEMENT = "ProvisionAgreement"; + public static final String REPORTING_TAXONOMY = "ReportingTaxonomy"; + public static final String REPORTING_TAXONOMY_MAP = "ReportingTaxonomyMap"; + public static final String VALUE_LIST = "ValueList"; + public static final String GEO_CODELIST = "GeographicCodelist"; + public static final String GEOGRID_CODELIST = "GeoGridCodelist"; + + public static final String INCLUSIVE_CODE_SELECTION = "InclusiveCodeSelection"; + public static final String EXCLUSIVE_CODE_SELECTION = "ExclusiveCodeSelection"; + public static final String MEMBER_VALUE = "MemberValue"; + public static final String CODELIST_EXTENSION = "CodelistExtension"; + public static final String CASCADE_VALUES = "cascadeValues"; + + public static final String COM_ANNOTATIONS = "Annotations"; + public static final String COM_ANNOTATION = "Annotation"; + public static final String COM_ANNOTATION_TITLE = "AnnotationTitle"; + public static final String COM_ANNOTATION_TYPE = "AnnotationType"; + public static final String COM_ANNOTATION_URL = "AnnotationURL"; + public static final String COM_ANNOTATION_TEXT = "AnnotationText"; + public static final String COM_ANNOTATION_VALUE = "AnnotationValue"; + + public static final String COM_NAME = "Name"; + public static final String COM_DESCRIPTION = "Description"; + public static final String COM_LINK = "Link"; + public static final String STR_CODE = "Code"; + public static final String STRUCTURE_PARENT = "Parent"; + + public static final String CANNOT_BE_NULL = " cannot be null!"; + public static final String STRUCTURE_URL = "structureUrl"; + public static final String SERVICE_URL = "serviceUrl"; + + public static final String HAS_FORMAL_LEVELS = "hasFormalLevels"; + public static final String DOES_NOT_SUPPORT_ELEMENT = "does not support element: "; + + + public static final String CODE = "Code"; + public static final String LEVEL = "Level"; + public static final String CODING_FORMAT = "CodingFormat"; + public static final String HIERARCHICAL_CODE = "HierarchicalCode"; + + public static final String CONCEPT = "Concept"; + + public static final String CORE_REPRESENTATION = "CoreRepresentation"; + public static final String ENUMERATION = "Enumeration"; + public static final String TEXT_FORMAT = "TextFormat"; + public static final String SENTINEL_VALUE = "SentinelValue"; + public static final String ISOCONCEPT_REFERENCE = "ISOConceptReference"; + public static final String CONCEPT_AGENCY = "ConceptAgency"; + public static final String CONCEPT_SCHEME_ID = "ConceptSchemeID"; + public static final String CONCEPT_ID = "ConceptID"; + + public static final String DATA_STRUCTURE_COMPONENTS = "DataStructureComponents"; + public static final String METADATA = "Metadata"; + + + public static final String ATTRIBUTE_LIST = "AttributeList"; + public static final String METADATA_ATTRIBUTE_USAGE = "MetadataAttributeUsage"; + public static final String METADATA_ATTRIBUTE_REFERENCE = "MetadataAttributeReference"; + public static final String ATTRIBUTE = "Attribute"; + public static final String ASSIGNMENT_STATUS = "assignmentStatus"; + public static final String MANDATORY = "Mandatory"; + public static final String CONDITIONAL = "Conditional"; + public static final String MEASURE_RELATIONSHIP = "MeasureRelationship"; + public static final String PRIMARY_MEASURE = "PrimaryMeasure"; + public static final String DIMENSION = "Dimension"; + public static final String ATTACHMENT_GROUP = "AttachmentGroup"; + public static final String OBSERVATION = "Observation"; + public static final String GROUP = "Group"; + public static final String MEASURE_LIST = "MeasureList"; + public static final String LOCAL_REPRESENTATION = "LocalRepresentation"; + + public static final String DIMENSION_LIST = "DimensionList"; + public static final String TIME_DIMENSION = "TimeDimension"; + public static final String POSITION = "position"; + public static final String ATTRIBUTE_RELATIONSHIP = "AttributeRelationship"; + public static final String NONE_RELATIONSHIP = "None"; + public static final BidiMap MAP_FACET_TYPE = new DualHashBidiMap<>(); + public static final String CONCEPT_IDENTITY = "ConceptIdentity"; + public static final String CONCEPT_ROLE = "ConceptRole"; + public static final String LANG = "lang"; + public static final String STRUCTURE_UPPER = "Structure"; + public static final String MIN_OCCURS = "minOccurs"; + public static final String MAX_OCCURS = "maxOccurs"; + public static final String IS_PRESENTATIONAL = "isPresentational"; + public static final String METADATA_ATTRIBUTE = "MetadataAttribute"; + public static final String METADATA_ATTRIBUTE_LIST = "MetadataAttributeList"; + public static final String METADATA_STRUCTURE_COMPONENTS = "MetadataStructureComponents"; + + public static final String TARGET = "Target"; + public static final String SOURCE_DATA_TYPE = "SourceDataType"; + public static final String TARGET_DATA_TYPE = "TargetDataType"; + public static final String SOURCE_CODELIST = "SourceCodelist"; + public static final String TARGET_CODELIST = "TargetCodelist"; + public static final String REPRESENTATION_MAPPING = "RepresentationMapping"; + public static final String TARGET_VALUE = "TargetValue"; + public static final String SOURCE_VALUE = "SourceValue"; + + public static final String MEASURE_DESCRIPTOR_ID = "MeasureDescriptor"; + public static final String ATTRIBUTE_DESCRIPTOR_ID = "AttributeDescriptor"; + public static final String METADATA_ATTRIBUTE_DESCRIPTOR_ID = "MetadataAttributeDescriptor"; + public static final String DIMENSION_DESCRIPTOR_ID = "DimensionDescriptor"; + public static final String GROUP_DIMENSION = "GroupDimension"; + public static final String DIMENSION_REFERENCE = "DimensionReference"; + + public static final String SOURCE = "Source"; + public static final String COMPONENT_MAP = "ComponentMap"; + public static final String FIXED_VALUE_MAP = "FixedValueMap"; + public static final String VALUE = "Value"; + public static final String FREQUENCY_ID = "FrequencyId"; + public static final String DATE_PATTERN = "DatePattern"; + public static final String FREQUENCY_FORMAT_MAPPING = "FrequencyFormatMapping"; + public static final String DATE_PATTERN_MAP = "DatePatternMap"; + public static final String EPOCH_MAP = "EpochMap"; + public static final String FREQUENCY_DIMENSION = "FrequencyDimension"; + public static final String TARGET_FREQUENCY_ID = "TargetFrequencyID"; + public static final String MAPPED_FREQUENCIES = "MappedFrequencies"; + public static final String CATEGORY = "Category"; + + public static final BidiMap STRING_RESOLVE_PERIOD_MAP = new DualHashBidiMap<>(); + + public static final BidiMap STRING_EPOCH_PERIOD_MAP = new DualHashBidiMap<>(); + + public static final BidiMap CASCADE_VALUE_TYPE_STRING = new DualHashBidiMap<>(); + + public static final BidiMap CONSTRAINT_ROLE_STRING = new DualHashBidiMap<>(); + public static final String XML_LANG = "xml:lang"; + + public static final String CONTACT = "Contact"; + public static final String NAME = "Name"; + public static final String DEPARTMENT = "Department"; + public static final String ROLE = "Role"; + public static final String TELEPHONE = "Telephone"; + public static final String FAX = "Fax"; + public static final String X_400 = "X400"; + public static final String EMAIL = "Email"; + public static final String AGENCY = "Agency"; + public static final String URI = "URI"; + public static final String ITEM_MAP = "ItemMap"; + + public static final String DATA_CONSUMER = "DataConsumer"; + public static final String DATA_CONSUMERS = "DATA_CONSUMERS"; + public static final String DATA_PROVIDER = "DataProvider"; + public static final String DATA_PROVIDERS = "DATA_PROVIDERS"; + public static final String METADATA_PROVIDERS = "METADATA_PROVIDERS"; + public static final String ORGANISATION_UNIT_SCHEMES = "OrganisationUnitSchemes"; + + public static final String LINKED_HIERARCHY = "LinkedHierarchy"; + public static final String LINKED_OBJECT = "LinkedObject"; + public static final String CONTEXT_OBJECT = "ContextObject"; + public static final String ROLE_ATTR = "role"; + public static final String CONSTRAINT_ATTACHMENT = "ConstraintAttachment"; + public static final String RELEASE_CALENDAR = "ReleaseCalendar"; + public static final String METADATA_TARGET_REGION = "MetadataTargetRegion"; + public static final String OFFSET = "Offset"; + public static final String PERIODICITY = "Periodicity"; + public static final String TOLERANCE = "Tolerance"; + public static final String IS_INCLUSIVE = "isInclusive"; + public static final String START_PERIOD = "StartPeriod"; + public static final String END_PERIOD = "EndPeriod"; + public static final String BEFORE_PERIOD = "BeforePeriod"; + public static final String AFTER_PERIOD = "AfterPeriod"; + public static final String TIME_RANGE = "TimeRange"; + public static final String INCLUDE = "include"; + public static final String METADATA_TARGET = "metadataTarget"; + public static final String REPORT = "report"; + public static final String COMPONENT = "Component"; + public static final String KEY_VALUE = "KeyValue"; + public static final String REMOVE_PREFIX = "removePrefix"; + public static final String ALLOWED = "Allowed"; + public static final String METADATA_PROVIDER = "MetadataProvider"; + public static final String METADATA_SET = "MetadataSet"; + public static final String METADATA_STRUCTURE = "MetadataStructure"; + public static final String METADATAFLOW = "Metadataflow"; + public static final String METADATA_PROVISION_AGREEMENT = "MetadataProvisionAgreement"; + public static final String ORGANISATION_UNIT_SCHEME = "OrganisationUnitScheme"; + public static final String ORGANISATION_UNIT = "OrganisationUnit"; + public static final String LOCAL_ID = "localID"; + public static final String TARGET_STEP = "TargetStep"; + public static final String CONDITION = "Condition"; + public static final String INPUT = "Input"; + public static final String OUTPUT = "Output"; + public static final String SOFTWARE_LANGUAGE = "softwareLanguage"; + public static final String SOFTWARE_VERSION = "softwareVersion"; + public static final String SOFTWARE_PACKAGE = "softwarePackage"; + public static final String DESCRIPTION = "Description"; + public static final String OBJECT_REFERENCE = "ObjectReference"; + public static final String COMPUTATION = "Computation"; + public static final String TRANSITION = "Transition"; + public static final String PROCESS_STEP = "ProcessStep"; + public static final String VALUE_ITEM = "ValueItem"; + + public static final String REPORTING_CATEGORY = "ReportingCategory"; + public static final String PROVISIONING_METADATA = "ProvisioningMetadata"; + public static final String STRUCTURAL_METADATA = "StructuralMetadata"; + public static final String IS_INCLUDED = "isIncluded"; + public static final String KEY = "Key"; + public static final String CUBE_REGION = "CubeRegion"; + public static final String DATA_KEY_SET = "DataKeySet"; + public static final String TEXT_TYPE = "textType"; + public static final String ID = "id"; + public static final String NAME_LOWER = "name"; + public static final String NAMES = "names"; + public static final String VERSION = "version"; + public static final String AGENCY_ID = "agencyID"; + public static final String DESCRIPTION_LOWER = "description"; + public static final String DESCRIPTIONS = "descriptions"; + public static final String VALID_TO = "validTo"; + public static final String VALID_FROM = "validFrom"; + public static final String IS_PARTIAL = "isPartial"; + public static final String IS_EXTERNAL_REFERENCE = "isExternalReference"; + public static final String URN = "urn"; + public static final String TYPE = "type"; + public static final String REL = "rel"; + public static final String URL = "url"; + public static final String DEFAULT_VERSION = "1.0"; + + public static final String HIERARCHY = "Hierarchy"; + public static final String OBS_VALUE = "OBS_VALUE"; + + static { + STRING_RESOLVE_PERIOD_MAP.put("startOfPeriod", ResolvePeriod.START_OF_PERIOD); + STRING_RESOLVE_PERIOD_MAP.put("endOfPeriod", ResolvePeriod.END_OF_PERIOD); + STRING_RESOLVE_PERIOD_MAP.put("midPeriod", ResolvePeriod.MID_PERIOD); + } + + static { + CASCADE_VALUE_TYPE_STRING.put(CascadeValue.TRUE, "true"); + CASCADE_VALUE_TYPE_STRING.put(CascadeValue.FALSE, "false"); + CASCADE_VALUE_TYPE_STRING.put(CascadeValue.EXCLUDE_ROOT, "excluderoot"); + } + + + static { + CONSTRAINT_ROLE_STRING.put(ConstraintRoleType.ALLOWABLE_CONTENT, ALLOWED); + CONSTRAINT_ROLE_STRING.put(ConstraintRoleType.ACTUAL_CONTENT, "Actual"); + } + + static { + STRING_EPOCH_PERIOD_MAP.put("day", EpochPeriodType.DAY); + STRING_EPOCH_PERIOD_MAP.put("second", EpochPeriodType.SECOND); + STRING_EPOCH_PERIOD_MAP.put("microsecond", EpochPeriodType.MICROSECOND); + STRING_EPOCH_PERIOD_MAP.put("millisecond", EpochPeriodType.MILLISECOND); + STRING_EPOCH_PERIOD_MAP.put("nanosecond", EpochPeriodType.NANOSECOND); + } + + static { + MAP_FACET_TYPE.put(FacetType.INTERVAL.name(), "interval"); + MAP_FACET_TYPE.put(FacetType.DECIMALS.name(), "decimals"); + MAP_FACET_TYPE.put(FacetType.IS_MULTILINGUAL.name(), "isMultilingual"); + MAP_FACET_TYPE.put(FacetType.END_VALUE.name(), "endValue"); + MAP_FACET_TYPE.put(FacetType.END_TIME.name(), "endTime"); + MAP_FACET_TYPE.put(FacetType.IS_SEQUENCE.name(), "isSequence"); + MAP_FACET_TYPE.put(FacetType.MAX_LENGTH.name(), "maxLength"); + MAP_FACET_TYPE.put(FacetType.MAX_VALUE.name(), "maxValue"); + MAP_FACET_TYPE.put(FacetType.MIN_LENGTH.name(), "minLength"); + MAP_FACET_TYPE.put(FacetType.MIN_VALUE.name(), "minValue"); + MAP_FACET_TYPE.put(FacetType.PATTERN.name(), "pattern"); + MAP_FACET_TYPE.put(FacetType.SENTINEL_VALUES.name(), "sentinelValues"); + MAP_FACET_TYPE.put(FacetType.START_TIME.name(), "startTime"); + MAP_FACET_TYPE.put(FacetType.START_VALUE.name(), "startValue"); + MAP_FACET_TYPE.put(FacetType.TIME_INTERVAL.name(), "timeInterval"); + } + + + private XmlConstants() { + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/XmlWriter.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/XmlWriter.java new file mode 100644 index 0000000..7641d0b --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/XmlWriter.java @@ -0,0 +1,60 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; + +public abstract class XmlWriter { + + protected NameableWriter nameableWriter; + protected AnnotableWriter annotableWriter; + protected CommonAttributesWriter commonAttributesWriter; + + protected XmlWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter) { + this.nameableWriter = nameableWriter; + this.annotableWriter = annotableWriter; + this.commonAttributesWriter = commonAttributesWriter; + } + + protected abstract void writeAttributes(T artefact, XMLStreamWriter writer) throws XMLStreamException; + + protected abstract void writeCustomAttributeElements(T artefact, XMLStreamWriter writer) throws XMLStreamException; + + protected abstract String getName(T artefact); + + protected abstract String getNamePlural(); + + + public Optional getWritableArtefactStructureClass() { + // if there is a need to find writer by its maintainable artefact type + return Optional.empty(); + } + protected void writeCommon(T artefact, XMLStreamWriter writer) throws XMLStreamException { + annotableWriter.write(artefact, writer); + nameableWriter.write(artefact, writer); + } + + protected abstract Set extractArtefacts(Artefacts artefacts); + + void write(MaintainableArtefact maintainableArtefact, XMLStreamWriter writer) throws XMLStreamException { + T artefact = (T) maintainableArtefact; + writer.writeStartElement(XmlConstants.STR + getName(artefact)); + writeAttributes(artefact, writer); + writeCommon(artefact, writer); + writeCustomAttributeElements(artefact, writer); + writer.writeEndElement(); + cleanData(); + } + + private void cleanData() { + //individual for each artefact + } +} diff --git a/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/XmlWriterUtils.java b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/XmlWriterUtils.java new file mode 100644 index 0000000..7b2d136 --- /dev/null +++ b/sdmx-ml21/src/main/java/com/epam/jsdmx/xml21/structure/writer/XmlWriterUtils.java @@ -0,0 +1,142 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import java.net.URI; +import java.net.URL; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Map; +import java.util.Objects; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.InternationalUri; +import com.epam.jsdmx.infomodel.sdmx30.Version; + +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.util.Strings; + +public final class XmlWriterUtils { + + private XmlWriterUtils() { + } + + public static void writeArtefactReference(XMLStreamWriter writer, String artefactReferenceName, String reference) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STR + artefactReferenceName); + writeCharacters(reference, writer); + writer.writeEndElement(); + } + + public static void writeInternationalString(InternationalString internationalString, XMLStreamWriter writer, String localName) throws XMLStreamException { + if (internationalString != null) { + Map stringsWithLocales = internationalString.getAll(); + for (Map.Entry stringLocale : stringsWithLocales.entrySet()) { + if (stringLocale != null) { + writer.writeStartElement(localName); + writer.writeAttribute(XmlConstants.XML_LANG, stringLocale.getKey()); + String value = stringLocale.getValue(); + writeCharacters(value, writer); + writer.writeEndElement(); + } + } + } + } + + public static void writeCharacters(String value, XMLStreamWriter writer) throws XMLStreamException { + try { + writer.writeCharacters(Objects.requireNonNullElse(value, Strings.EMPTY)); + } catch (XMLStreamException e) { + if (StringUtils.contains(e.getMessage(), "Invalid white space character (")) { + writer.writeCharacters(removeInvalidChars(value)); + } else { + throw e; + } + } + } + + private static String removeInvalidChars(String value) { + return value.replaceAll("[\\x00-\\x1F\\x7F-\\x9F]", ""); + } + + public static void writeInternationalUri(InternationalUri internationalUri, XMLStreamWriter writer, String localName) throws XMLStreamException { + if (internationalUri != null) { + Map stringsWithLocales = internationalUri.getAll(); + for (Map.Entry stringLocale : stringsWithLocales.entrySet()) { + if (stringLocale != null) { + writer.writeStartElement(localName); + writer.writeAttribute(XmlConstants.XML_LANG, stringLocale.getKey()); + URI value = stringLocale.getValue(); + writeCharacters(value.toString(), writer); + writer.writeEndElement(); + } + } + } + } + + public static void writeVersion(Version version, XMLStreamWriter writer) throws XMLStreamException { + if (version != null) { + writer.writeAttribute(XmlConstants.VERSION, version.getValue()); + } + } + + public static void writeUrn(String urn, XMLStreamWriter writer) throws XMLStreamException { + if (urn != null) { + writer.writeAttribute(XmlConstants.URN, urn); + } + } + + public static void writeUri(URI uri, XMLStreamWriter writer) throws XMLStreamException { + if (uri != null) { + writer.writeAttribute(XmlConstants.URI, uri.toString()); + } + } + + public static void writeUrl(URL url, XMLStreamWriter writer, String urlName) throws XMLStreamException { + if (url != null) { + writer.writeAttribute(urlName, url.toString()); + } + } + + public static void writeInstant(Instant instant, XMLStreamWriter writer, String instanceName) throws XMLStreamException { + if (instant != null) { + writer.writeAttribute(instanceName, instant.toString()); + } + } + + public static void writeMandatoryAttribute(String attribute, XMLStreamWriter writer, String attributeName) throws XMLStreamException { + if (attribute != null) { + writer.writeAttribute(attributeName, attribute); + } else { + throw new IllegalArgumentException(attributeName + XmlConstants.CANNOT_BE_NULL); + } + } + + public static void writeAttributeIfNotNull(String attribute, XMLStreamWriter writer, String attributeName) throws XMLStreamException { + if (attribute != null) { + writer.writeAttribute(attributeName, attribute); + } + } + + public static void writeIdUriAttributes(XMLStreamWriter writer, + String id, + URI uri) throws XMLStreamException { + writeMandatoryAttribute(id, writer, XmlConstants.ID); + writeUri(uri, writer); + } + + public static String instantToDateString(Instant time) { + DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE.withZone(ZoneId.systemDefault()); + if (time != null) { + return formatter.format(time); + } + return null; + } + + public static void writeIsFinal(XMLStreamWriter writer, Version version) throws XMLStreamException { + if (version != null) { + writer.writeAttribute("isFinal", Boolean.toString(version.isStable())); + } + } +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/MaintainableArtifactsTestUtils.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/MaintainableArtifactsTestUtils.java new file mode 100644 index 0000000..d117acc --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/MaintainableArtifactsTestUtils.java @@ -0,0 +1,1411 @@ +package com.epam.jsdmx.xml21.structure; + +import java.net.URI; +import java.net.URISyntaxException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.AfterPeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.AgencyImpl; +import com.epam.jsdmx.infomodel.sdmx30.AgencySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Annotation; +import com.epam.jsdmx.infomodel.sdmx30.AnnotationImpl; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseFacetImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseTextFormatRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.BeforePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.CascadeValue; +import com.epam.jsdmx.infomodel.sdmx30.CategorisationImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategoryImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodingFormat; +import com.epam.jsdmx.infomodel.sdmx30.CodingFormatImpl; +import com.epam.jsdmx.infomodel.sdmx30.ComponentMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.ComponentValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.ComputationImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConstraintRoleType; +import com.epam.jsdmx.infomodel.sdmx30.Contact; +import com.epam.jsdmx.infomodel.sdmx30.ContactImpl; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionImpl; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionKeyImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataKeyImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySet; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySetImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.DatePatternMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponentImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.EnumeratedRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.EpochMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.EpochPeriodType; +import com.epam.jsdmx.infomodel.sdmx30.ExclusiveCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.Facet; +import com.epam.jsdmx.infomodel.sdmx30.FacetType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueTypeRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.FixedValueMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.FrequencyFormatMappingImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCode; +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeoGridCodelist; +import com.epam.jsdmx.infomodel.sdmx30.GeoGridCodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeographicCodelist; +import com.epam.jsdmx.infomodel.sdmx30.GeographicCodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.GridCode; +import com.epam.jsdmx.infomodel.sdmx30.GridCodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.GroupDimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchicalCodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyAssociation; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyAssociationImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableObjectSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.InclusiveCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.IsoConceptReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.infomodel.sdmx30.ItemMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.LevelImpl; +import com.epam.jsdmx.infomodel.sdmx30.ListReferenceValueRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.LocalisedMemberValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.MappedValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.MappingRoleType; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeRefImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderScheme; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProvisionAgreement; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProvisionAgreementImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataTargetRegion; +import com.epam.jsdmx.infomodel.sdmx30.MetadataTargetRegionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.ObservationRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationSchemeMap; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationSchemeMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitImpl; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitScheme; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.infomodel.sdmx30.Process; +import com.epam.jsdmx.infomodel.sdmx30.ProcessArtefactImpl; +import com.epam.jsdmx.infomodel.sdmx30.ProcessImpl; +import com.epam.jsdmx.infomodel.sdmx30.ProcessStep; +import com.epam.jsdmx.infomodel.sdmx30.ProcessStepImpl; +import com.epam.jsdmx.infomodel.sdmx30.ProvisionAgreement; +import com.epam.jsdmx.infomodel.sdmx30.ProvisionAgreementImpl; +import com.epam.jsdmx.infomodel.sdmx30.RangePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendar; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendarImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReportingCategoryImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomy; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyMap; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMappingImpl; +import com.epam.jsdmx.infomodel.sdmx30.ResolvePeriod; +import com.epam.jsdmx.infomodel.sdmx30.SentinelValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.TargetValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.TimeDimensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.TimeRangePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.TransitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.ValueItemImpl; +import com.epam.jsdmx.infomodel.sdmx30.ValueList; +import com.epam.jsdmx.infomodel.sdmx30.ValueListImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; +import com.epam.jsdmx.serializer.sdmx30.common.Header; + +public final class MaintainableArtifactsTestUtils { + + /** + * sets common fields for maintainable artefact + * + * @param artefact - artefact to set fields for + */ + public static void setMaintainableArtefact(MaintainableArtefactImpl artefact) { + artefact.setId("ARTEFACT"); + artefact.setVersion(Version.createFromString("1.2")); + artefact.setOrganizationId("IMF"); + artefact.setName(new InternationalString("Maintanable artefact")); + artefact.getName().add(Locale.CANADA_FRENCH.toLanguageTag(), "artefact"); + String date = "2022-07-17T10:11:16Z"; + + artefact.setValidTo(date); + artefact.setValidFrom(date); + artefact.setDescription(new InternationalString("Some artefact")); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("1"); + annotation.setText(new InternationalString("text")); + annotation.setValue("VALUE"); + annotation.setType("type1"); + artefact.addAnnotation(annotation); + } + + /** + * @return Categorisation object + */ + public static CategorisationImpl buildCategorisation() { + CategorisationImpl categorisation = new CategorisationImpl(); + setMaintainableArtefact(categorisation); + IdentifiableArtefactReferenceImpl cateogryReference = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.CATEGORY, + "CAT_TARGET" + ); + + categorisation.setCategorizedBy(cateogryReference); + MaintainableArtefactReference artefactReference = new MaintainableArtefactReference( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.CODELIST + ); + categorisation.setCategorizedArtefact(artefactReference); + return categorisation; + } + + /** + * @return CategoryScheme object + */ + public static CategorySchemeImpl buildCategoryScheme() { + CategorySchemeImpl categoryScheme = new CategorySchemeImpl(); + setMaintainableArtefact(categoryScheme); + categoryScheme.setPartial(true); + CategoryImpl category = new CategoryImpl(); + category.setDescription(new InternationalString("description")); + category.setId("Category-1"); + category.setName(new InternationalString("Category1")); + category.setDescription(new InternationalString("description category 1")); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot"); + category.setAnnotations(List.of(annotation)); + CategoryImpl category2 = new CategoryImpl(); + category2.setDescription(new InternationalString("description category2")); + category2.setId("Category-2"); + category2.setName(new InternationalString("Category2")); + AnnotationImpl annotation2 = new AnnotationImpl(); + annotation2.setId("Annot2"); + category2.setAnnotations(List.of(annotation, annotation2)); + CategoryImpl category3 = new CategoryImpl(); + category3.setDescription(new InternationalString("description category3")); + category3.setId("Category-3"); + category3.setName(new InternationalString("Category3")); + category.setHierarchy(List.of(category2, category3)); + + CategoryImpl category4 = new CategoryImpl(); + category4.setId("Category-4"); + category4.setName(new InternationalString("Category4")); + categoryScheme.setItems(List.of(category, category4)); + return categoryScheme; + } + + /** + * @return Codelist object + */ + public static CodelistImpl buildCodeList() { + CodelistImpl codelist = new CodelistImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(codelist); + codelist.setPartial(true); + codelist.setExtensions(getExtensions()); + fillCodes(codelist); + return codelist; + } + + private static void fillCodes(CodelistImpl codelist) { + CodeImpl code = new CodeImpl(); + code.setDescription(new InternationalString("code 1 desc")); + code.setId("CODE1"); + code.setName(new InternationalString("code 1")); + code.setParentId("CODE2"); + CodeImpl code2 = new CodeImpl(); + code2.setDescription(new InternationalString("code 2 desc")); + code2.setId("CODE2"); + code2.setName(new InternationalString("code 2")); + code2.setHierarchy(List.of(code)); + codelist.setItems(List.of(code, code2)); + } + + private static List getExtensions() { + CodelistExtensionImpl inclusiveCodeListExtension = fillInclusiveCodeListExtension(); + CodelistExtensionImpl exclusiveCodeListExtension = fillExclusiveCodeListExtension(); + return List.of(inclusiveCodeListExtension, exclusiveCodeListExtension); + } + + private static CodelistExtensionImpl fillExclusiveCodeListExtension() { + CodelistExtensionImpl codelistExtension = new CodelistExtensionImpl(); + ExclusiveCodeSelectionImpl exclusiveCodeSelection = new ExclusiveCodeSelectionImpl(); + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setCascadeValue(CascadeValue.FALSE); + memberValue.setValue("mem2"); + exclusiveCodeSelection.setMembers(List.of(memberValue)); + return fillCodeListExtension(codelistExtension, exclusiveCodeSelection); + } + + private static CodelistExtensionImpl fillInclusiveCodeListExtension() { + CodelistExtensionImpl codelistExtension = new CodelistExtensionImpl(); + InclusiveCodeSelectionImpl inclusiveCodeSelection = new InclusiveCodeSelectionImpl(); + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setCascadeValue(CascadeValue.TRUE); + memberValue.setValue("mem1"); + inclusiveCodeSelection.setMembers(List.of(memberValue)); + return fillCodeListExtension(codelistExtension, inclusiveCodeSelection); + } + + private static CodelistExtensionImpl fillCodeListExtension(CodelistExtensionImpl codelistExtension, BaseCodeSelectionImpl codeSelection) { + codelistExtension.setPrefix("PREF2"); + MaintainableArtefactReference maintainableReference = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)"); + codelistExtension.setCodelist(maintainableReference); + codelistExtension.setCodeSelection(codeSelection); + return codelistExtension; + } + + /** + * @return ConceptScheme object + */ + public static ConceptSchemeImpl buildConceptScheme() { + ConceptSchemeImpl conceptScheme = new ConceptSchemeImpl(); + setMaintainableArtefact(conceptScheme); + ConceptImpl concept = new ConceptImpl(); + concept.setId("COUNTRY"); + concept.setName(new InternationalString("Country")); + IsoConceptReferenceImpl isoConceptReference = new IsoConceptReferenceImpl(); + isoConceptReference.setConceptId("Conn"); + isoConceptReference.setAgency("QHB"); + isoConceptReference.setSchemeId("Schema"); + concept.setIsoConceptReference(isoConceptReference); + concept.setCoreRepresentation(getRepresentation()); + conceptScheme.setItems(List.of(concept)); + conceptScheme.setPartial(true); + return conceptScheme; + } + + private static Representation getRepresentation() { + Set facetSet = new HashSet<>(); + BaseFacetImpl facet1 = new BaseFacetImpl(); + BaseFacetImpl facet2 = new BaseFacetImpl(); + facet1.setValueType(FacetValueType.ALPHA); + SentinelValueImpl sentinelValue = new SentinelValueImpl(); + sentinelValue.setValue("val"); + sentinelValue.setName(new InternationalString("sent")); + sentinelValue.setDescription(new InternationalString("sentinel descr")); + facet2.setSentinelValues(List.of(sentinelValue)); + facet2.setType(FacetType.SENTINEL_VALUES); + facet2.setValueType(FacetValueType.ALPHA); + facetSet.addAll(List.of(facet1, facet2)); + return new BaseTextFormatRepresentationImpl(facetSet); + } + + /** + * @return DataConstraint object + */ + public static DataConstraintImpl buildDataConstraint() { + DataConstraintImpl dataConstraint = new DataConstraintImpl(); + setMaintainableArtefact(dataConstraint); + dataConstraint.setConstraintRoleType(ConstraintRoleType.ALLOWABLE_CONTENT); + + LocalisedMemberValueImpl localisedMemberValue = new LocalisedMemberValueImpl(); + localisedMemberValue.setValue("local"); + localisedMemberValue.setLocale("en"); + + MemberValueImpl selectionValue1 = new MemberValueImpl(); + selectionValue1.setValue("selectionValue1"); + + MemberSelectionImpl memberSelection1 = new MemberSelectionImpl(); + memberSelection1.setSelectionValues(List.of(localisedMemberValue, selectionValue1)); + memberSelection1.setComponentId("some component id 1"); + memberSelection1.setIncluded(true); + memberSelection1.setRemovePrefix(true); + + MemberValueImpl selectionValue2 = new MemberValueImpl(); + selectionValue2.setValue("selectionValue2"); + selectionValue2.setCascadeValue(CascadeValue.TRUE); + selectionValue2.setValidTo(Instant.parse("2020-05-12T12:00:00.000000Z")); + selectionValue2.setValidFrom(Instant.parse("2020-04-12T12:00:00.000000Z")); + MemberValueImpl selectionValue5 = new MemberValueImpl(); + selectionValue5.setValue("selectionValue5"); + + MemberSelectionImpl memberSelection2 = new MemberSelectionImpl(); + memberSelection2.setSelectionValues(List.of(selectionValue2, selectionValue5)); + memberSelection2.setComponentId("some component id 2"); + memberSelection2.setIncluded(true); + memberSelection2.setRemovePrefix(true); + + BeforePeriodImpl selectionValue3 = new BeforePeriodImpl(); + selectionValue3.setPeriod("2020"); + AfterPeriodImpl selectionValue4 = new AfterPeriodImpl(); + selectionValue4.setPeriod("2021"); + + CubeRegionKeyImpl cubeRegionKey1 = new CubeRegionKeyImpl(); + cubeRegionKey1.setComponentId("123"); + cubeRegionKey1.setIncluded(true); + cubeRegionKey1.setRemovePrefix(true); + cubeRegionKey1.setValidFrom(Instant.parse("2020-04-12T12:00:00.000000Z")); + cubeRegionKey1.setValidTo(Instant.parse("2022-04-12T12:00:00.000000Z")); + cubeRegionKey1.setSelectionValues(List.of(selectionValue3, selectionValue4)); + + CubeRegionImpl cubeRegion = new CubeRegionImpl(); + cubeRegion.setIncluded(true); + cubeRegion.setMemberSelections(List.of(memberSelection1, memberSelection2)); + cubeRegion.setCubeRegionKeys(List.of(cubeRegionKey1)); + cubeRegion.setAnnotations(getAnnotations()); + + dataConstraint.setCubeRegions(List.of(cubeRegion)); + dataConstraint.setReleaseCalendar(createReleaseCalendar()); + dataConstraint.setDataContentKeys(List.of(createDataKeySets())); + dataConstraint.setConstrainedArtefacts(List.of(buildProvisionAgreement().getDataProvider())); + + return dataConstraint; + } + + /** + * @return DataStructureDefinition object + */ + public static DataStructureDefinitionImpl buildDataStructureDefinition() { + DataStructureDefinitionImpl dataStructureDefinition = new DataStructureDefinitionImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(dataStructureDefinition); + MaintainableArtefactReference maintainableReference = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)"); + dataStructureDefinition.setMetadataStructure(maintainableReference); + return dataStructureDefinition; + } + + /** + * @return MetadataStructureDefinition object + */ + public static MetadataStructureDefinitionImpl buildMetadataStructureDefinition() { + MetadataStructureDefinitionImpl metadataStructureDefinition = new MetadataStructureDefinitionImpl(); + setMaintainableArtefact(metadataStructureDefinition); + MetadataAttributeDescriptorImpl metadataAttributeDescriptor = new MetadataAttributeDescriptorImpl(); + metadataAttributeDescriptor.setId("MetadataAttributeDescriptor"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot-1"); + MetadataAttributeImpl metadataAttribute = getMetadataAttribute("meta-1", "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)"); + metadataAttribute.setHierarchy(List.of(getMetadataAttribute("meta-2", "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)"))); + metadataAttributeDescriptor.setComponents(List.of(metadataAttribute)); + metadataAttributeDescriptor.addAnnotation(annotation); + metadataStructureDefinition.setAttributeDescriptor(metadataAttributeDescriptor); + return metadataStructureDefinition; + } + + private static MetadataAttributeImpl getMetadataAttribute(String id, String reference) { + MetadataAttributeImpl metadataAttribute = new MetadataAttributeImpl(); + metadataAttribute.setId(id); + metadataAttribute.setMaxOccurs(20); + metadataAttribute.setMinOccurs(10); + metadataAttribute.setPresentational(true); + Representation representation = new EnumeratedRepresentationImpl( + new MaintainableArtefactReference(reference)); + metadataAttribute.setLocalRepresentation(representation); + metadataAttribute.setConceptIdentity( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DIM")); + return metadataAttribute; + } + + /** + * @return AttributeDescriptor + */ + public static AttributeDescriptorImpl fillAttributeDescriptor() { + AttributeDescriptorImpl attributeDescriptor = new AttributeDescriptorImpl(); + attributeDescriptor.setId("AttributeDescriptor"); + fillMetadata(attributeDescriptor); + fillComponents(attributeDescriptor); + return attributeDescriptor; + } + + + private static void fillComponents(AttributeDescriptorImpl attributeDescriptor) { + DataAttributeImpl dataAttribute = new DataAttributeImpl(); + dataAttribute.setId("DA1"); + dataAttribute.setMinOccurs(0); + DimensionRelationshipImpl dimensionRelationship = new DimensionRelationshipImpl(); + dimensionRelationship.setDimensions(List.of("DIM1")); + dimensionRelationship.setGroupKeys(List.of("GroupDimensionDescriptor2")); + dataAttribute.setAttributeRelationship(dimensionRelationship); + BaseFacetImpl baseFacet = new BaseFacetImpl(); + baseFacet.setValueType(FacetValueType.ALPHA_NUMERIC); + dataAttribute.setLocalRepresentation(new BaseTextFormatRepresentationImpl(Set.of(baseFacet))); + dataAttribute.setConceptIdentity(new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE")); + dataAttribute.setConceptRoles( + List.of( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE"), + new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE") + )); + MeasureRelationshipImpl measureRelationship = new MeasureRelationshipImpl(); + measureRelationship.setMeasures(List.of("MO")); + dataAttribute.setMeasureRelationship(measureRelationship); + attributeDescriptor.setComponents(List.of(dataAttribute)); + } + + private static void fillMetadata(AttributeDescriptorImpl attributeDescriptor) { + MetadataAttributeRefImpl attributeRef1 = new MetadataAttributeRefImpl(); + attributeRef1.setId("REFERENCE-1"); + attributeRef1.setMetadataRelationship(new ObservationRelationshipImpl()); + MetadataAttributeRefImpl attributeRef2 = new MetadataAttributeRefImpl(); + attributeRef2.setId("REFERENCE-2"); + DimensionRelationshipImpl dimensionRelationship = new DimensionRelationshipImpl(); + dimensionRelationship.setDimensions(List.of("dim1", "dim2")); + attributeRef2.setMetadataRelationship(dimensionRelationship); + MetadataAttributeRefImpl attributeRef3 = new MetadataAttributeRefImpl(); + attributeRef3.setId("REFERENCE-3"); + attributeRef3.setMetadataRelationship(null); + attributeDescriptor.setMetadataAttributes(List.of(attributeRef1, attributeRef2, attributeRef3)); + } + + /** + * @return List + */ + public static List fillListGroupDimensionDescriptor() { + GroupDimensionDescriptorImpl groupDimensionDescriptor1 = new GroupDimensionDescriptorImpl(); + AnnotationImpl annotation1 = new AnnotationImpl(); + annotation1.setId("id1"); + annotation1.setValue("val"); + AnnotationImpl annotation2 = new AnnotationImpl(); + annotation2.setId("id2"); + annotation2.setValue("val"); + groupDimensionDescriptor1.setId("GroupDimensionDescriptor1"); + groupDimensionDescriptor1.setAnnotations(List.of(annotation1, annotation2)); + groupDimensionDescriptor1.setDimensions(List.of("DIM1", "TIME_PERIOD")); + + GroupDimensionDescriptorImpl groupDimensionDescriptor2 = new GroupDimensionDescriptorImpl(); + groupDimensionDescriptor2.setId("GroupDimensionDescriptor2"); + groupDimensionDescriptor2.setDimensions(List.of("DIM1")); + + return List.of(groupDimensionDescriptor1, groupDimensionDescriptor2); + } + + /** + * @return DimensionDescriptor + */ + public static DimensionDescriptorImpl fillDimensionDescriptor() { + DimensionDescriptorImpl dimensionDescriptor = new DimensionDescriptorImpl(); + dimensionDescriptor.setId("DimensionDescriptor"); + fillDimensionComponents(dimensionDescriptor); + return dimensionDescriptor; + } + + private static void fillDimensionComponents(DimensionDescriptorImpl dimensionDescriptor) { + DimensionImpl dimensionComponent = new DimensionImpl(); + dimensionComponent.setOrder(1); + dimensionComponent.setId("DIM1"); + dimensionComponent.setConceptRoles(List.of(new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE"))); + EnumeratedRepresentationImpl enumeratedRepresentation = new EnumeratedRepresentationImpl( + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)")); + dimensionComponent.setLocalRepresentation(enumeratedRepresentation); + dimensionComponent.setConceptIdentity( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE")); + DimensionComponentImpl dimensionTimeComponent = new TimeDimensionImpl(); + dimensionTimeComponent.setId("TIME_PERIOD"); + dimensionTimeComponent.setOrder(2); + dimensionTimeComponent.setConceptIdentity( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE")); + BaseFacetImpl baseFacet = new BaseFacetImpl(); + baseFacet.setValueType(FacetValueType.BASIC_TIME_PERIOD); + dimensionTimeComponent.setLocalRepresentation(new BaseTextFormatRepresentationImpl(Set.of(baseFacet))); + dimensionDescriptor.setComponents(List.of(dimensionComponent, dimensionTimeComponent)); + } + + /** + * @return MeasureDescriptor + */ + public static MeasureDescriptorImpl fillMeasureDescriptor() { + MeasureDescriptorImpl measureDescriptor = new MeasureDescriptorImpl(); + measureDescriptor.setId("MeasureDescriptor"); + fillMeasureComponents(measureDescriptor); + return measureDescriptor; + } + + private static void fillMeasureComponents(MeasureDescriptorImpl measureDescriptor) { + MeasureImpl measure = new MeasureImpl(); + measure.setId("OBS_VALUE"); + measure.setConceptIdentity(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE")); + measure.setConceptRoles( + List.of( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE"), + new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE") + )); + BaseFacetImpl baseFacet = new BaseFacetImpl(); + baseFacet.setValueType(FacetValueType.BASIC_TIME_PERIOD); + measure.setLocalRepresentation(new BaseTextFormatRepresentationImpl(Set.of(baseFacet))); + measureDescriptor.setComponents(List.of(measure)); + } + + /** + * @return Hierarchy object + */ + public static HierarchyImpl buildHierarchy() { + HierarchyImpl hierarchy = new HierarchyImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(hierarchy); + hierarchy.setHasFormalLevels(true); + HierarchicalCodeImpl code = new HierarchicalCodeImpl(); + code.setId("id"); + code.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1")); + code.setLevelId("levId"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("id"); + code.setAnnotations(List.of(annotation)); + String dateStr = "2022-07-17T10:11:16.345Z"; + code.setValidTo(Instant.parse(dateStr)); + code.setValidFrom(Instant.parse(dateStr)); + HierarchicalCodeImpl code2 = new HierarchicalCodeImpl(); + code2.setId("hi-2"); + code2.setLevelId("levId"); + code2.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL2")); + code2.setValidTo(Instant.parse(dateStr)); + code2.setValidFrom(Instant.parse(dateStr)); + hierarchy.setCodes(List.of(code, code2)); + LevelImpl level = new LevelImpl(); + level.setDescription(new InternationalString("hierarchy desc")); + level.setName(new InternationalString("hierarchy name")); + level.setId("levId"); + level.setCodeFormat(List.of(fillListOfCodingFormats().get(0), fillListOfCodingFormats().get(1), fillListOfCodingFormats().get(7))); + hierarchy.setLevel(level); + return hierarchy; + } + + public static HierarchyImpl buildHierarchyWithInnerHierarchy() { + HierarchyImpl hierarchy = new HierarchyImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(hierarchy); + hierarchy.setHasFormalLevels(true); + HierarchicalCodeImpl code = new HierarchicalCodeImpl(); + code.setId("id"); + code.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1")); + code.setLevelId("Lev1"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("id"); + code.setAnnotations(List.of(annotation)); + String dateStr = "2022-07-17T10:11:16.345Z"; + code.setValidTo(Instant.parse(dateStr)); + code.setValidFrom(Instant.parse(dateStr)); + HierarchicalCodeImpl hierarchicalCode = new HierarchicalCodeImpl(); + hierarchicalCode.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1")); + hierarchicalCode.setId("1"); + hierarchicalCode.setValidTo(Instant.parse(dateStr)); + hierarchicalCode.setValidFrom(Instant.parse(dateStr)); + code.setHierarchicalCodes(List.of(hierarchicalCode)); + hierarchy.setCodes(List.of(code)); + LevelImpl level = new LevelImpl(); + level.setDescription(new InternationalString("hierarchy desc")); + level.setName(new InternationalString("hierarchy name")); + level.setId("levId"); + level.setCodeFormat(List.of(fillListOfCodingFormats().get(0), fillListOfCodingFormats().get(1))); + hierarchy.setLevel(level); + LevelImpl levelUn = new LevelImpl(); + levelUn.setId("levUn"); + levelUn.setName(new InternationalString("underLevel")); + level.setChild(levelUn); + return hierarchy; + } + + private static List fillListOfCodingFormats() { + List codingFormatList = new ArrayList<>(); + codingFormatList.add(addCodingFormat(FacetType.INTERVAL, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.IS_SEQUENCE, String.valueOf(true))); + codingFormatList.add(addCodingFormat(FacetType.MAX_LENGTH, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.MIN_LENGTH, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.MAX_VALUE, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.MIN_VALUE, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.PATTERN, "a")); + codingFormatList.add(addCodingFormat(FacetType.START_VALUE, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.END_VALUE, String.valueOf(1))); + + CodingFormatImpl codingFormat = new CodingFormatImpl(); + codingFormat.setCodingFormat(new BaseFacetImpl(FacetValueType.fromValue("Alpha"))); + codingFormatList.add(codingFormat); + return codingFormatList; + } + + private static CodingFormat addCodingFormat(FacetType facetType, String value) { + CodingFormatImpl codingFormat = new CodingFormatImpl(); + BaseFacetImpl baseFacet = new BaseFacetImpl(); + baseFacet.setType(facetType); + baseFacet.setValue(value); + codingFormat.setCodingFormat(baseFacet); + return codingFormat; + } + + /** + * @return Metadataflow object + */ + public static MetadataflowImpl buildMetadataFlow() { + MetadataflowImpl metadataflow = new MetadataflowImpl(); + setMaintainableArtefact(metadataflow); + metadataflow.setStructure(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=IMF:METADATA(1.0.0)")); + IdentifiableObjectSelectionImpl objectSelection = new IdentifiableObjectSelectionImpl(); + MaintainableArtefactReference maintainableArtefactReference = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)"); + + MaintainableArtefactReference maintainableArtefactReference2 = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.3)"); + objectSelection.setResolvesTo(List.of(maintainableArtefactReference, maintainableArtefactReference2)); + metadataflow.setSelections(List.of(objectSelection)); + return metadataflow; + } + + /** + * @return Dataflow object + */ + public static DataflowImpl buildDataFlow() { + DataflowImpl dataflow = new DataflowImpl(); + dataflow.setId("DF"); + dataflow.setStructure(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)")); + setMaintainableArtefact(dataflow); + return dataflow; + } + + /** + * @return AgencyScheme + */ + + public static AgencySchemeImpl buildAgencyScheme() { + AgencySchemeImpl agencyScheme = new AgencySchemeImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(agencyScheme); + agencyScheme.setId("AGENCIES"); + agencyScheme.setOrganizationId("SDMX"); + agencyScheme.setVersion(Version.createFromString("1.0")); + AgencyImpl agency1 = createAgency("AG-1"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot"); + agency1.setAnnotations(List.of(annotation)); + AgencyImpl agency2 = createAgency("AG-2"); + + + agencyScheme.setItems(List.of(agency1, agency2)); + return agencyScheme; + } + + private static AgencyImpl createAgency(String id) { + AgencyImpl agency1 = new AgencyImpl(); + agency1.setId(id); + agency1.setName(new InternationalString("Agency")); + agency1.setDescription(new InternationalString("Agency")); + + List contacts = getContacts(); + + agency1.setContacts(contacts); + return agency1; + } + + private static List getContacts() { + ContactImpl contact1 = new ContactImpl(); + contact1.setName("AG_1"); + contact1.setTelephone("9458673082"); + contact1.setFax("somedatafax"); + contact1.setEmail("test@email.com"); + contact1.setOrganizationUnit("IT"); + Map resp = new HashMap<>(); + resp.put("en", "writing"); + resp.put("fr", "ecrire"); + contact1.setResponsibility(new InternationalString(resp)); + contact1.setX400("X400"); + + ContactImpl contact2 = new ContactImpl(); + contact2.setName("AG_2"); + contact2.setTelephone("9458673082"); + contact2.setFax("somedatafax2"); + contact2.setEmail("test@email.com"); + contact2.setOrganizationUnit("IT"); + contact2.setResponsibility(new InternationalString(resp)); + contact2.setX400("X400"); + return List.of(contact1, contact2); + } + + /** + * @return CategorySchemeMap + */ + + public static CategorySchemeMapImpl buildCategorySchemeMap() { + CategorySchemeMapImpl categorySchemeMap = new CategorySchemeMapImpl(); + setMaintainableArtefact(categorySchemeMap); + categorySchemeMap.setSource(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:CatScheme(1.0)")); + categorySchemeMap.setTarget(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:CatScheme(1.1)")); + ItemMap itemMap = createItemMap("IM-1", "S-1"); + ItemMap itemMap2 = createItemMap("IM-2", "S-2"); + categorySchemeMap.setItemMaps(List.of(itemMap, itemMap2)); + return categorySchemeMap; + } + + private static ItemMap createItemMap(String target, String source) { + ItemMapImpl itemMap = new ItemMapImpl(); + itemMap.setTarget(target); + itemMap.setSource(source); + itemMap.setValidTo(Instant.parse("2022-07-17T00:00:00Z")); + itemMap.setValidFrom(Instant.parse("2022-07-17T00:00:00Z")); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Ann"); + itemMap.setAnnotations(List.of(annotation)); + return itemMap; + } + + /** + * @return ConceptSchemeMap + */ + + public static ConceptSchemeMapImpl buildConceptSchemeMap() { + ConceptSchemeMapImpl conceptSchemeMap = new ConceptSchemeMapImpl(); + setMaintainableArtefact(conceptSchemeMap); + conceptSchemeMap.setSource(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ConScheme(1.0)")); + conceptSchemeMap.setTarget(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ConScheme(1.1)")); + ItemMap itemMap = createItemMap("IM-1", "S-1"); + ItemMap itemMap2 = createItemMap("IM-2", "S-2"); + conceptSchemeMap.setItemMaps(List.of(itemMap, itemMap2)); + return conceptSchemeMap; + } + + /** + * @return DataConsumerSchemeImpl + */ + public static DataConsumerSchemeImpl buildDataConsumerScheme() { + DataConsumerSchemeImpl dataConsumerScheme = new DataConsumerSchemeImpl(); + setMaintainableArtefact(dataConsumerScheme); + dataConsumerScheme.setVersion(Version.createFromString("1.0")); + dataConsumerScheme.setId("DATA_CONSUMERS"); + DataConsumerImpl dataConsumer = new DataConsumerImpl(); + dataConsumer.setId("DC"); + dataConsumer.setName(new InternationalString("Data Consumer")); + dataConsumer.setDescription(new InternationalString("Data Consumer description")); + dataConsumer.setContacts(getContacts()); + dataConsumerScheme.setItems(List.of(dataConsumer)); + return dataConsumerScheme; + } + + /** + * @return RepresentationMap object + */ + public static RepresentationMapImpl buildRepresentationMap() { + RepresentationMapImpl representationMap = new RepresentationMapImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(representationMap); + fillSource(representationMap, "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_SOURCE(1.0)"); + fillTarget(representationMap, "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_TARGET(1.0)"); + fillRepresentationMappings(representationMap, "2022-07-17T00:00:00.000Z"); + return representationMap; + } + + public static void fillTarget(RepresentationMapImpl representationMap, String referenceUrn) { + ListReferenceValueRepresentationImpl valueRepresentation = new ListReferenceValueRepresentationImpl(); + valueRepresentation.setReference(new MaintainableArtefactReference(referenceUrn)); + representationMap.setTarget(List.of(valueRepresentation)); + } + + public static void fillSource(RepresentationMapImpl representationMap, String referenceUrn) { + ListReferenceValueRepresentationImpl valueRepresentation = new ListReferenceValueRepresentationImpl(); + valueRepresentation.setReference(new MaintainableArtefactReference(referenceUrn)); + FacetValueTypeRepresentationImpl valueRepresentation2 = new FacetValueTypeRepresentationImpl(); + valueRepresentation2.setType(FacetValueType.DATE_TIME); + representationMap.setSource(List.of(valueRepresentation, valueRepresentation2)); + } + + public static void fillRepresentationMappings(RepresentationMapImpl representationMap, String date) { + RepresentationMappingImpl representationMapping = new RepresentationMappingImpl(); + Instant instant = Instant.parse(date); + representationMapping.setValidFrom(instant); + representationMapping.setValidTo(instant); + fillSourceValues(representationMapping); + fillTargetValues(representationMapping); + representationMap.setRepresentationMappings(List.of(representationMapping)); + } + + static void fillTargetValues(RepresentationMappingImpl representationMapping) { + TargetValueImpl targetValue1 = new TargetValueImpl(); + targetValue1.setValue("targetValue1"); + TargetValueImpl targetValue2 = new TargetValueImpl(); + targetValue2.setValue("targetValue2"); + representationMapping.setTargetValues(List.of(targetValue1, targetValue2)); + } + + static void fillSourceValues(RepresentationMappingImpl representationMapping) { + MappedValueImpl mappedValue = new MappedValueImpl(); + mappedValue.setValue("mappedValue"); + mappedValue.setRegEx(true); + mappedValue.setStartIndex(0); + mappedValue.setEndIndex(10); + representationMapping.setSourceValues(List.of(mappedValue)); + } + + /** + * @return StructureMap object + */ + public static StructureMapImpl buildStructureMap() { + StructureMapImpl structureMap = new StructureMapImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(structureMap); + structureMap.setSource(new MaintainableArtefactReference("DataFSource", "EPM", "3.0", StructureClassImpl.DATAFLOW)); + structureMap.setTarget(new MaintainableArtefactReference("DataFTarget", "EPM", "3.0", StructureClassImpl.DATAFLOW)); + fillEpochMap(structureMap); + fillFixedValueMap(structureMap); + fillComponentMap(structureMap); + fillDatePattern(structureMap); + return structureMap; + } + + static void fillDatePattern(StructureMapImpl structureMap) { + DatePatternMapImpl datePatternMap = new DatePatternMapImpl(); + datePatternMap.setLocale("EN"); + datePatternMap.setSourcePattern("SOURCE"); + datePatternMap.setId("DP1"); + datePatternMap.setResolvePeriod(ResolvePeriod.MID_PERIOD); + FrequencyFormatMappingImpl frequencyFormatMapping1 = getFrequencyFormatMapping("CODE_1", "2022-11", "FR1"); + FrequencyFormatMappingImpl frequencyFormatMapping2 = getFrequencyFormatMapping("CODE_2", "2022-11", "FR2"); + datePatternMap.setMappedFrequencies(List.of(frequencyFormatMapping1, frequencyFormatMapping2)); + datePatternMap.setFrequencyDimension("Frequency_dim"); + structureMap.setDatePatternMaps(List.of(datePatternMap)); + } + + private static FrequencyFormatMappingImpl getFrequencyFormatMapping(String freqCode, String datePattern, String id) { + FrequencyFormatMappingImpl frequencyFormatMapping = new FrequencyFormatMappingImpl(); + frequencyFormatMapping.setFrequencyCode(freqCode); + frequencyFormatMapping.setDatePattern(datePattern); + frequencyFormatMapping.setId(id); + return frequencyFormatMapping; + } + + static void fillComponentMap(StructureMapImpl structureMap) { + + ComponentMapImpl componentMapDP = new ComponentMapImpl(); + componentMapDP.setSource(List.of("CompMapEpochS")); + componentMapDP.setTarget(List.of("CompMapEpochT")); + IdentifiableArtefactReferenceImpl reference = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.EPOCH_MAP, + "EPOCH1" + ); + componentMapDP.setRepresentationMap(reference); + + + ComponentMapImpl componentMapEpoch = new ComponentMapImpl(); + componentMapEpoch.setSource(List.of("CompMapDPS")); + componentMapEpoch.setTarget(List.of("CompMapDPT")); + IdentifiableArtefactReferenceImpl reference2 = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.DATE_PATTERN_MAP, + "DP1" + ); + componentMapEpoch.setRepresentationMap(reference2); + + ComponentMapImpl componentMaRep = new ComponentMapImpl(); + componentMaRep.setSource(List.of("CompMapRepS")); + componentMaRep.setTarget(List.of("CompMapRepT")); + MaintainableArtefactReference reference3 = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)"); + componentMaRep.setRepresentationMap(reference3); + + structureMap.setComponentMaps(List.of(componentMapEpoch, componentMapDP, componentMaRep)); + } + + static void fillFixedValueMap(StructureMapImpl structureMap) { + FixedValueMapImpl fixedValueMap = new FixedValueMapImpl(); + fixedValueMap.setRole(MappingRoleType.TARGET); + fixedValueMap.setComponent("STRUC_ID"); + fixedValueMap.setValue("value"); + structureMap.setFixedComponentMaps(List.of(fixedValueMap)); + } + + static void fillEpochMap(StructureMapImpl structureMap) { + EpochMapImpl epochMap = new EpochMapImpl(); + epochMap.setEpochPeriod(EpochPeriodType.MICROSECOND); + Instant instant = Instant.parse("2022-07-17T10:11:16Z"); + epochMap.setBasePeriod(instant); + epochMap.setId("EPOCH1"); + epochMap.setResolvePeriod(ResolvePeriod.MID_PERIOD); + FrequencyFormatMappingImpl frequencyFormatMapping3 = getFrequencyFormatMapping("CODE_3", "2022-11", "FR3"); + epochMap.setMappedFrequencies(List.of(frequencyFormatMapping3)); + epochMap.setFrequencyDimension("Frequency_dim"); + structureMap.setEpochMaps(List.of(epochMap)); + } + + /** + * @return Header + */ + public static Header buildHeader() throws URISyntaxException { + Header header = new Header(); + header.setId("IDREF8124"); + URI uri = new URI("https://raw.githubusercontent.com/sdmx-twg/sdmx-json/master/metadata-message/tools/schemas/2.0.0/sdmx-json-metadata-schema.json"); + header.setSchema(uri); + Instant instant = Instant.parse("2021-11-02T09:47:41Z"); + header.setPrepared(instant); + Party sender = new Party(); + sender.setId("unknown"); + header.setSender(sender); + Locale locale = new Locale("en"); + header.setContentLanguages(List.of(locale)); + return header; + } + + public static DataProviderSchemeImpl buildDataProviderScheme() { + + DataProviderSchemeImpl dataProviderScheme = new DataProviderSchemeImpl(); + setMaintainableArtefact(dataProviderScheme); + dataProviderScheme.setVersion(Version.createFromString("1.0")); + dataProviderScheme.setId("DATA_PROVIDERS"); + dataProviderScheme.setPartial(true); + + DataProviderImpl dataProvider = new DataProviderImpl(); + dataProvider.setContacts(getContacts()); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Ann"); + annotation.setTitle("Val"); + dataProvider.setAnnotations(List.of(annotation)); + dataProvider.setId("Prov"); + dataProvider.setName(new InternationalString("D_P")); + + dataProviderScheme.setItems(List.of(dataProvider)); + return dataProviderScheme; + } + + public static MetadataProviderScheme buildMetadataProviderScheme() { + + MetadataProviderSchemeImpl metadataProviderScheme = new MetadataProviderSchemeImpl(); + setMaintainableArtefact(metadataProviderScheme); + metadataProviderScheme.setVersion(Version.createFromString("1.0")); + metadataProviderScheme.setId("METADATA_PROVIDERS"); + metadataProviderScheme.setPartial(true); + + MetadataProviderImpl metadataProvider = new MetadataProviderImpl(); + metadataProvider.setContacts(getContacts()); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Ann"); + annotation.setValue("Val"); + metadataProvider.setAnnotations(List.of(annotation)); + metadataProvider.setId("Prov"); + metadataProvider.setName(new InternationalString("MD_P")); + + metadataProviderScheme.setItems(List.of(metadataProvider)); + return metadataProviderScheme; + } + + public static HierarchyAssociation buildHierarchyAssociation() { + HierarchyAssociationImpl hierarchyAssociation = new HierarchyAssociationImpl(); + setMaintainableArtefact(hierarchyAssociation); + hierarchyAssociation.setLinkedHierarchy(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.codelist.Hierarchy=IMF:ARTEFACT(1.2)")); + hierarchyAssociation.setContextObject(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)")); + hierarchyAssociation.setLinkedObject(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.3)")); + return hierarchyAssociation; + } + + public static MetadataConstraintImpl buildMetadataConstraint(boolean isJson) { + MetadataConstraintImpl metadataConstraint = new MetadataConstraintImpl(); + setMaintainableArtefact(metadataConstraint); + metadataConstraint.setConstraintRoleType(ConstraintRoleType.ALLOWABLE_CONTENT); + metadataConstraint.setMetadataTargetRegions(createMetadataTargetRegions(isJson)); + metadataConstraint.setReleaseCalendar(createReleaseCalendar()); + metadataConstraint.setConstrainedArtefacts(createMetadataConstrainedArtefacts()); + return metadataConstraint; + } + + private static List createMetadataConstrainedArtefacts() { + IdentifiableArtefactReferenceImpl maintainableArtefactReference = new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=IMF:ARTEFACT(1.2)"); + return List.of(maintainableArtefactReference); + } + + private static List createMetadataTargetRegions(boolean isJson) { + MetadataTargetRegionImpl metadataTargetRegion = new MetadataTargetRegionImpl(); + metadataTargetRegion.setIncluded(true); + metadataTargetRegion.setValidTo(Instant.parse("2022-07-17T10:11:16Z")); + metadataTargetRegion.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + List memberSelectionList = getMemberSelections(false, isJson); + metadataTargetRegion.setMemberSelections(memberSelectionList); + + return List.of(metadataTargetRegion); + } + + private static List getMemberSelections(boolean isSimple, boolean isJson) { + MemberSelectionImpl memberSelection = new MemberSelectionImpl(); + memberSelection.setIncluded(false); + memberSelection.setRemovePrefix(true); + memberSelection.setComponentId("MS"); + + MemberValueImpl memberValue; + if (isSimple) { + memberValue = getMemberValueSimple(); + } else { + memberValue = getMemberValue(); + } + + LocalisedMemberValueImpl localisedMemberValue = new LocalisedMemberValueImpl(); + localisedMemberValue.setValue("local"); + localisedMemberValue.setLocale("en"); + + memberSelection.setSelectionValues(List.of(memberValue, localisedMemberValue)); + + MemberSelectionImpl memberSelection2 = new MemberSelectionImpl(); + memberSelection2.setIncluded(false); + memberSelection2.setRemovePrefix(true); + memberSelection2.setComponentId("MS2"); + BeforePeriodImpl beforePeriod = new BeforePeriodImpl(); + beforePeriod.setInclusive(true); + beforePeriod.setPeriod("2023"); + if (!isJson) { + beforePeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + beforePeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + } + + AfterPeriodImpl afterPeriod = new AfterPeriodImpl(); + afterPeriod.setInclusive(false); + afterPeriod.setPeriod("2028"); + afterPeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + afterPeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + + RangePeriodImpl rangePeriod = new RangePeriodImpl(); + TimeRangePeriodImpl timeRangePeriod = new TimeRangePeriodImpl(); + timeRangePeriod.setInclusive(true); + timeRangePeriod.setPeriod("2022"); + timeRangePeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + timeRangePeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + + rangePeriod.setStartPeriod(timeRangePeriod); + timeRangePeriod.setInclusive(false); + rangePeriod.setEndPeriod(timeRangePeriod); + rangePeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + rangePeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + + memberSelection2.setSelectionValues(List.of(beforePeriod)); + return List.of(memberSelection, memberSelection2); + } + + private static MemberValueImpl getMemberValue() { + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setValue("MEM"); + memberValue.setCascadeValue(CascadeValue.EXCLUDE_ROOT); + memberValue.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + memberValue.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + return memberValue; + } + + private static MemberValueImpl getMemberValueSimple() { + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setValue("MEM"); + return memberValue; + } + + private static ReleaseCalendar createReleaseCalendar() { + ReleaseCalendarImpl releaseCalendar = new ReleaseCalendarImpl(); + releaseCalendar.setOffset("Offset"); + releaseCalendar.setTolerance("Tolerance"); + releaseCalendar.setPeriodicity("Periodicity"); + return releaseCalendar; + } + + private static DataKeySet createDataKeySets() { + DataKeySetImpl dataKeySet = new DataKeySetImpl(); + dataKeySet.setIncluded(true); + DataKeyImpl dataKey = new DataKeyImpl(); + dataKey.setIncluded(true); + ComponentValueImpl componentValue = new ComponentValueImpl(); + componentValue.setIncluded(true); + componentValue.setComponentId("C1"); + componentValue.setRemovePrefix(true); + componentValue.setValue("Value"); + dataKey.setKeyValues(List.of(componentValue)); + dataKey.setMemberSelections(getMemberSelections(true, true)); + dataKey.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + dataKey.setValidTo(Instant.parse("2022-07-17T10:11:16Z")); + dataKeySet.setKeys(List.of(dataKey)); + + return dataKeySet; + } + + public static MetadataProvisionAgreement buildMetadataProvisionAgreement() { + MetadataProvisionAgreementImpl metadataProvisionAgreement = new MetadataProvisionAgreementImpl(); + setMaintainableArtefact(metadataProvisionAgreement); + metadataProvisionAgreement.setControlledStructureUsage(new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=IMF:ARTEFACT(1.2)")); + metadataProvisionAgreement.setMetadataProvider(new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.base.MetadataProvider=IMF:METADATA_PROVIDERS(1.0).PR")); + return metadataProvisionAgreement; + } + + public static OrganisationSchemeMap buildOrganisationSchemeMap() { + OrganisationSchemeMapImpl organisationSchemeMap = new OrganisationSchemeMapImpl(); + setMaintainableArtefact(organisationSchemeMap); + organisationSchemeMap.setSource(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.base.AgencyScheme=SDMX:AGENCIES(1.0)")); + organisationSchemeMap.setTarget(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.base.AgencyScheme=SDMX:AGENCIES(1.0)")); + ItemMap itemMap = createItemMap("IM-1", "S-1"); + ItemMap itemMap2 = createItemMap("IM-2", "S-2"); + organisationSchemeMap.setItemMaps(List.of(itemMap, itemMap2)); + return organisationSchemeMap; + } + + public static Process buildProcess() { + ProcessImpl process = new ProcessImpl(); + setMaintainableArtefact(process); + List processSteps = new ArrayList<>(); + ProcessStepImpl processStep = new ProcessStepImpl(); + processStep.setId("ProcStep"); + processStep.setName(new InternationalString("ProcessStep")); + processStep.setDescription(new InternationalString("ProcessStep description")); + + ProcessArtefactImpl processArtefact = new ProcessArtefactImpl(); + processArtefact.setLocalId("Loc"); + processArtefact.setArtefact(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.process.ProcessStep=IMF:Artefact(1.0)")); + processArtefact.setAnnotations(getAnnotations()); + processStep.setInputs(List.of(processArtefact)); + processStep.setOutputs(List.of(processArtefact)); + + TransitionImpl transition = new TransitionImpl(); + transition.setId("Trans"); + transition.setLocalId("Loc"); + transition.setTargetProcessStep("ST"); + transition.setCondition(new InternationalString("Doo")); + processStep.setTransitions(List.of(transition)); + + ComputationImpl computation = new ComputationImpl(); + computation.setLocalId("LocId"); + computation.setSoftwareLanguage("SoftwareLanguage"); + computation.setSoftwarePackage("SoftwarePackage"); + computation.setSoftwareVersion("SoftwareVersion"); + computation.setAnnotations(getAnnotations()); + computation.setDescription(new InternationalString("Computation Description")); + processStep.setComputation(computation); + + ProcessStepImpl processStepChild = new ProcessStepImpl(); + processStepChild.setId("ProcessChild"); + processStepChild.setAnnotations(getAnnotations()); + processStepChild.setName(new InternationalString("ProcessStepChild")); + processStep.setChildren(List.of(processStepChild)); + processStep.setAnnotations(getAnnotations()); + processSteps.add(processStep); + process.setSteps(processSteps); + + return process; + } + + + public static ProvisionAgreement buildProvisionAgreement() { + ProvisionAgreementImpl provisionAgreement = new ProvisionAgreementImpl(); + setMaintainableArtefact(provisionAgreement); + provisionAgreement.setControlledStructureUsage( + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=IMF:ARTEFACT(1.2)")); + provisionAgreement.setDataProvider( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP")); + return provisionAgreement; + } + + public static ReportingTaxonomy buildReportingTaxonomy() { + ReportingTaxonomyImpl reportingTaxonomy = new ReportingTaxonomyImpl(); + setMaintainableArtefact(reportingTaxonomy); + ReportingCategoryImpl reportingCategory1 = new ReportingCategoryImpl(); + reportingCategory1.setId("RC-1"); + reportingCategory1.setName(new InternationalString("ReportingCat")); + reportingCategory1.setDescription(new InternationalString("ReportingCat description")); + reportingCategory1.setAnnotations(getAnnotations()); + reportingCategory1.setFlows(List.of( + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataS2(3.0)"), + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataS1(3.0)") + + )); + ReportingCategoryImpl reportingCategory2 = new ReportingCategoryImpl(); + reportingCategory2.setId("RC-2"); + reportingCategory2.setName(new InternationalString("ReportingCat2")); + reportingCategory2.setDescription(new InternationalString("ReportingCat2 description")); + reportingCategory2.setAnnotations(getAnnotations()); + reportingCategory2.setStructures(List.of( + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=EPM:DataS2(3.0)"), + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=EPM:DataS1(3.0)") + )); + reportingCategory1.setHierarchy(List.of(reportingCategory2)); + reportingTaxonomy.setItems(List.of(reportingCategory1)); + return reportingTaxonomy; + } + + public static ReportingTaxonomyMap buildReportingTaxonomyMap() { + ReportingTaxonomyMapImpl reportingTaxonomyMap = new ReportingTaxonomyMapImpl(); + setMaintainableArtefact(reportingTaxonomyMap); + reportingTaxonomyMap.setSource(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.categoryscheme.ReportingTaxonomy=SDMX:REP_SOURCE(1.0)")); + reportingTaxonomyMap.setTarget(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.categoryscheme.ReportingTaxonomy=SDMX:REP_TARGET(1.0)")); + ItemMap itemMap = createItemMap("IM-1", "S-1"); + ItemMap itemMap2 = createItemMap("IM-2", "S-2"); + reportingTaxonomyMap.setItemMaps(List.of(itemMap, itemMap2)); + return reportingTaxonomyMap; + } + + public static ValueList buildValueList() { + ValueListImpl valueList = new ValueListImpl(); + setMaintainableArtefact(valueList); + ValueItemImpl valueItem = new ValueItemImpl(); + valueItem.setId("VAL-1"); + Map names = new HashMap<>(); + names.put("en", "value"); + names.put("fr", "val"); + Map descriptions = new HashMap<>(); + descriptions.put("en", "it is value"); + descriptions.put("fr", "c'est val"); + valueItem.setName(new InternationalString(names)); + valueItem.setDescription(new InternationalString(descriptions)); + valueItem.setAnnotations(getAnnotations()); + + ValueItemImpl valueItem2 = new ValueItemImpl(); + valueItem2.setId("VAL-2"); + valueItem2.setName(new InternationalString("smth")); + valueItem2.setDescription(new InternationalString("smth description")); + valueItem2.setAnnotations(getAnnotations()); + valueList.setItems(List.of(valueItem, valueItem2)); + return valueList; + } + + public static DataConstraint buildDataConstraintXml() { + DataConstraintImpl dataConstraint = new DataConstraintImpl(); + setMaintainableArtefact(dataConstraint); + dataConstraint.setConstraintRoleType(ConstraintRoleType.ALLOWABLE_CONTENT); + CubeRegionImpl cubeRegion = new CubeRegionImpl(); + cubeRegion.setIncluded(true); + cubeRegion.setAnnotations(getAnnotations()); + CubeRegionKeyImpl cubeRegionKey = new CubeRegionKeyImpl(); + cubeRegionKey.setComponentId("CubeReg"); + cubeRegionKey.setIncluded(true); + cubeRegionKey.setRemovePrefix(true); + cubeRegionKey.setValidTo(Instant.parse("2022-07-17T10:11:16Z")); + cubeRegionKey.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + cubeRegionKey.setSelectionValues(List.of(getMemberValue())); + cubeRegion.setCubeRegionKeys(List.of(cubeRegionKey)); + cubeRegion.setMemberSelections(getMemberSelections(true, false)); + dataConstraint.setCubeRegions(List.of(cubeRegion)); + dataConstraint.setReleaseCalendar(createReleaseCalendar()); + DataKeySetImpl dataKeySet = new DataKeySetImpl(); + dataKeySet.setIncluded(true); + DataKeyImpl dataKey = new DataKeyImpl(); + dataKey.setIncluded(true); + ComponentValueImpl componentValue = new ComponentValueImpl(); + componentValue.setIncluded(true); + componentValue.setComponentId("C1"); + componentValue.setRemovePrefix(true); + componentValue.setValue("Value"); + dataKey.setKeyValues(List.of(componentValue)); + dataKey.setMemberSelections(getMemberSelections(true, false)); + dataKey.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + dataKey.setValidTo(Instant.parse("2022-07-17T10:11:16Z")); + dataKeySet.setKeys(List.of(dataKey)); + dataConstraint.setDataContentKeys(List.of(dataKeySet)); + IdentifiableArtefactReferenceImpl maintainableArtefactReference = new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).PR"); + dataConstraint.setConstrainedArtefacts(List.of(maintainableArtefactReference)); + return dataConstraint; + } + + public static GeographicCodelist buildGeographicCodelist() { + GeographicCodelistImpl geographicCodelist = new GeographicCodelistImpl(); + setMaintainableArtefact(geographicCodelist); + geographicCodelist.setItems(getGeoFeatureSetCodes()); + geographicCodelist.setExtensions(getExtensions()); + geographicCodelist.setPartial(true); + return geographicCodelist; + } + + private static List getGeoFeatureSetCodes() { + GeoFeatureSetCodeImpl geoFeatureSetCode1 = new GeoFeatureSetCodeImpl(); + geoFeatureSetCode1.setValue("Value1"); + geoFeatureSetCode1.setDescription(new InternationalString("code 1 desc")); + geoFeatureSetCode1.setId("CODE1"); + geoFeatureSetCode1.setName(new InternationalString("code 1")); + geoFeatureSetCode1.setParentId("CODE2"); + GeoFeatureSetCodeImpl geoFeatureSetCode2 = new GeoFeatureSetCodeImpl(); + geoFeatureSetCode2.setValue("Value2"); + geoFeatureSetCode2.setDescription(new InternationalString("code 2 desc")); + geoFeatureSetCode2.setId("CODE2"); + geoFeatureSetCode2.setName(new InternationalString("code 2")); + geoFeatureSetCode2.setHierarchy(List.of(geoFeatureSetCode1)); + return List.of(geoFeatureSetCode1, geoFeatureSetCode2); + } + + public static GeoGridCodelist buildGeoGridCodelist() { + GeoGridCodelistImpl geoGridCodelist = new GeoGridCodelistImpl(); + setMaintainableArtefact(geoGridCodelist); + geoGridCodelist.setItems(getGridCodes()); + geoGridCodelist.setExtensions(getExtensions()); + geoGridCodelist.setPartial(true); + geoGridCodelist.setGridDefinition("DEFINITION"); + return geoGridCodelist; + } + + private static List getGridCodes() { + GridCodeImpl gridCode = new GridCodeImpl(); + gridCode.setGeoCell("Value1"); + gridCode.setDescription(new InternationalString("code 1 desc")); + gridCode.setId("CODE1"); + gridCode.setName(new InternationalString("code 1")); + gridCode.setParentId("CODE2"); + GridCodeImpl gridCode2 = new GridCodeImpl(); + gridCode2.setGeoCell("Value2"); + gridCode2.setDescription(new InternationalString("code 2 desc")); + gridCode2.setId("CODE2"); + gridCode2.setName(new InternationalString("code 2")); + gridCode2.setHierarchy(List.of(gridCode)); + return List.of(gridCode, gridCode2); + } + + private static List getAnnotations() { + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot"); + return List.of(annotation); + } + + public static OrganisationUnitScheme buildOrganisationUnitScheme() { + OrganisationUnitSchemeImpl organisationUnitScheme = new OrganisationUnitSchemeImpl(); + setMaintainableArtefact(organisationUnitScheme); + organisationUnitScheme.setVersion(Version.createFromString("1.0")); + organisationUnitScheme.setPartial(true); + OrganisationUnitImpl organisationUnit = new OrganisationUnitImpl(); + organisationUnit.setAnnotations(getAnnotations()); + organisationUnit.setContacts(getContacts()); + organisationUnit.setId("OrgUnit"); + organisationUnit.setName(new InternationalString("OrganisationUnit")); + organisationUnit.setDescription(new InternationalString("OrganisationUnit description")); + OrganisationUnitImpl organisationUnit2 = new OrganisationUnitImpl(); + organisationUnit2.setId("OrgUnit2"); + organisationUnit2.setName(new InternationalString("OrganisationUnit")); + organisationUnit.setHierarchy(List.of(organisationUnit2)); + organisationUnitScheme.setItems(List.of(organisationUnit, organisationUnit2)); + return organisationUnitScheme; + } + +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/SdmxSourceCompatibilityTester.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/SdmxSourceCompatibilityTester.java new file mode 100644 index 0000000..c8c629b --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/SdmxSourceCompatibilityTester.java @@ -0,0 +1,26 @@ +package com.epam.jsdmx.xml21.structure; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.Set; +import java.util.function.Function; + +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; +import org.sdmxsource.sdmx.api.model.beans.base.MaintainableBean; +import org.sdmxsource.sdmx.api.util.ReadableDataLocation; +import org.sdmxsource.sdmx.structureparser.factory.SdmxStructureParserFactory; +import org.sdmxsource.util.factory.SdmxSourceReadableDataLocationFactory; + +public class SdmxSourceCompatibilityTester { + + public void test(String serialized, Function> extractor) { + final ReadableDataLocation readableDataLocation = new SdmxSourceReadableDataLocationFactory() + .getReadableDataLocation(new ByteArrayInputStream(serialized.getBytes(StandardCharsets.UTF_8))); + final SdmxStructureParserFactory structureParserFactory = new SdmxStructureParserFactory(); + SdmxBeans beans = structureParserFactory.getSdmxBeans(readableDataLocation); + assertThat(extractor.apply(beans)).isNotEmpty(); + } + +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/TestUtils.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/TestUtils.java new file mode 100644 index 0000000..3bc3b73 --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/TestUtils.java @@ -0,0 +1,48 @@ +package com.epam.jsdmx.xml21.structure; + +import java.io.File; +import java.io.IOException; + +import javax.xml.XMLConstants; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; + +import org.xml.sax.SAXException; + +public final class TestUtils { + + public static final String CODELIST_XML = "/xml/codelist.xml"; + public static final String HIERARCHIES_XML = "/xml/hierarchy.xml"; + public static final String HIERARCHIES_NAMES_XML = "/xml/hierarchy_names.xml"; + public static final String CONCEPT_SCHEME_XML = "/xml/concept-scheme.xml"; + public static final String CATEGORISATION_XML = "/xml/categorisation.xml"; + public static final String CATEGORISATION_HIERARCHY_XML = "/xml/categorisation_with_hierarchy_ref.xml"; + public static final String DSD_XML = "/xml/dsd.xml"; + public static final String DATAFLOW_XML = "/xml/dataflow.xml"; + public static final String CATEGORY_SCHEME_XML = "/xml/category-scheme.xml"; + public static final String AGENCY_SCHEME_XML = "/xml/agency-scheme.xml"; + public static final String DATA_CONSUMER_SCHEME_XML = "/xml/data-consumer-scheme.xml"; + public static final String DATA_PROVIDER_SCHEME_XML = "/xml/data-provider-scheme.xml"; + public static final String DATA_CONSTRAINTS_XML = "/xml/data-constraints.xml"; + public static final String META_DATA_CONSTRAINTS_XML = "/xml/metadata-constraints.xml"; + + public static final String ALL_XML = "/xml/all.xml"; + + public static boolean validateXMLSchema(File xsdPath, File xmlPath) { + + try { + SchemaFactory factory = + SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + Schema schema = factory.newSchema(xsdPath); + Validator validator = schema.newValidator(); + validator.validate(new StreamSource(xmlPath)); + } catch (IOException | SAXException e) { + System.out.println("Exception: " + e.getMessage()); + return false; + } + return true; + } + +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/BaseXmlWriterTest.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/BaseXmlWriterTest.java new file mode 100644 index 0000000..3444107 --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/BaseXmlWriterTest.java @@ -0,0 +1,159 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.time.Instant; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.serializer.common.TimeDimensionLocalRepresentationAdapter; +import com.epam.jsdmx.serializer.sdmx21.DataStructure30To21ComponentAdapter; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultHeaderProvider; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultReferenceAdapter; +import com.epam.jsdmx.serializer.sdmx30.common.Header; +import com.epam.jsdmx.xml21.structure.SdmxSourceCompatibilityTester; + +import lombok.SneakyThrows; +import org.junit.jupiter.api.BeforeEach; + +public abstract class BaseXmlWriterTest { + SdmxSourceCompatibilityTester sdmxSourceCompatibilityTester = new SdmxSourceCompatibilityTester(); + + NameableWriter nameableWriter = new NameableWriter(); + + AnnotableWriter annotableWriter = new AnnotableWriter(); + + ReferenceWriter referenceWriter = new ReferenceWriter(ref -> ref, new DefaultReferenceAdapter()); + + CommonAttributesWriter commonAttributesWriter = new CommonAttributesWriter(referenceWriter); + + ContactWriter contactWriter = new ContactWriter(); + + ReleaseCalenderWriter releaseCalenderWriter = new ReleaseCalenderWriter(); + + MemberSelectionWriter memberSelectionWriter = new MemberSelectionWriter(); + + OrganisationWriter organisationWriter = new OrganisationWriter(contactWriter, annotableWriter, nameableWriter); + + RepresentationWriter representationWriter = new RepresentationWriter(referenceWriter); + + DefaultHeaderProvider defaultHeaderProvider = mock(DefaultHeaderProvider.class); + + HeaderWriter headerWriter = new HeaderWriter(defaultHeaderProvider); + + DataStructure30To21ComponentAdapter dataStructure30To21ComponentAdapter = dsd -> dsd; + + TimeDimensionLocalRepresentationAdapter timeDimensionLocalRepresentationAdapter = dsd -> dsd; + + @BeforeEach + @SneakyThrows + void setup() { + Header header = new Header(); + header.setId("HED1"); + header.setName(new InternationalString("HeaderTest")); + header.setTest(true); + header.setReceivers(List.of(new Party("id", new InternationalString("str")))); + header.setSender(new Party("id", new InternationalString())); + header.setPrepared(Instant.parse("2023-04-17T10:11:16Z")); + when(defaultHeaderProvider.provide()).thenReturn(header); + } + + public CategorisationWriter createCategorisationWriter() { + return new CategorisationWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + referenceWriter + ); + } + + public CodelistWriter createCodelistWriter() { + return new CodelistWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + new CodeWriterImpl(referenceWriter, nameableWriter, annotableWriter) + ); + } + + public ConceptSchemeWriter createConceptSchemeWriter() { + return new ConceptSchemeWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + representationWriter + ); + } + + public CategorySchemeWriter createCategorySchemeWriter() { + return new CategorySchemeWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter + ); + } + + public DataflowWriter createDataflowWriter() { + return new DataflowWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + referenceWriter + ); + } + + public DataStructureDefinitionWriter createDataStructureDefinitionWriter() { + var attributeListWriter = new AttributeListWriter(annotableWriter, representationWriter, referenceWriter); + var dimensionListWriter = new DimensionListWriter(annotableWriter, representationWriter, referenceWriter); + var measureListWriter = new MeasureListWriter(annotableWriter, representationWriter, referenceWriter); + var groupDimensionListWriter = new GroupDimensionListWriter(annotableWriter, referenceWriter); + return new DataStructureDefinitionWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + attributeListWriter, + dimensionListWriter, + measureListWriter, + groupDimensionListWriter, + dataStructure30To21ComponentAdapter, + timeDimensionLocalRepresentationAdapter + ); + } + + public HierarchicalCodelistWriter createHierarchyWriter() { + return new HierarchicalCodelistWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + referenceWriter + ); + } + + public OrganisationSchemeWriter createOrganisationSchemeWriter() { + return new OrganisationSchemeWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + organisationWriter + ); + } + + public ContentConstraintWriter createContentConstraintWriter() { + DataKeySetsWriter dataKeySetsWriter = new DataKeySetsWriter(annotableWriter, memberSelectionWriter); + CubeRegionWriter cubeRegionWriter = new CubeRegionWriter(annotableWriter, memberSelectionWriter); + MetadataConstraintWriter metadataConstraintWriter = new MetadataConstraintWriter(memberSelectionWriter); + + return new ContentConstraintWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + referenceWriter, + releaseCalenderWriter, + dataKeySetsWriter, + cubeRegionWriter, + metadataConstraintWriter + ); + } +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/CategorisationWriterTest.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/CategorisationWriterTest.java new file mode 100644 index 0000000..32858fe --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/CategorisationWriterTest.java @@ -0,0 +1,109 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static com.epam.jsdmx.xml21.structure.MaintainableArtifactsTestUtils.setMaintainableArtefact; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorisationImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.xml21.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml21.structure.TestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; +import org.xml.sax.SAXException; + +class CategorisationWriterTest extends BaseXmlWriterTest { + + @Test + void writeCategorisation() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + CategorisationWriter categorisationWriter = createCategorisationWriter(); + + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + Xml21StructureWriter xmlStructureWriter = new Xml21StructureWriter( + bytes, + List.of(categorisationWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + CategorisationImpl categorisation = MaintainableArtifactsTestUtils.buildCategorisation(); + artefacts.getCategorisations().add(categorisation); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(TestUtils.CATEGORISATION_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + final String actual = bytes.toString(); + assertXMLEqual(expected, actual); + + sdmxSourceCompatibilityTester.test(actual, SdmxBeans::getCategorisations); + } + + @Test + void writeCategorisationWithHierarchyReference() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + CategorisationWriter categorisationWriter = createCategorisationWriter(); + + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + Xml21StructureWriter xmlStructureWriter = new Xml21StructureWriter( + bytes, + List.of(categorisationWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + CategorisationImpl categorisation = new CategorisationImpl(); + setMaintainableArtefact(categorisation); + IdentifiableArtefactReferenceImpl cateogryReference = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.CATEGORY, + "CAT_TARGET" + ); + + categorisation.setCategorizedBy(cateogryReference); + MaintainableArtefactReference artefactReference = new MaintainableArtefactReference( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.HIERARCHY + ); + categorisation.setCategorizedArtefact(artefactReference); + artefacts.getCategorisations().add(categorisation); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(TestUtils.CATEGORISATION_HIERARCHY_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + final String actual = bytes.toString(); + assertXMLEqual(expected, actual); + + sdmxSourceCompatibilityTester.test(actual, SdmxBeans::getCategorisations); + } +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/CategorySchemeWriterTest.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/CategorySchemeWriterTest.java new file mode 100644 index 0000000..23a534b --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/CategorySchemeWriterTest.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeImpl; +import com.epam.jsdmx.xml21.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml21.structure.TestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; +import org.xml.sax.SAXException; + +class CategorySchemeWriterTest extends BaseXmlWriterTest { + + @Test + void writeCategoryScheme() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + CategorySchemeWriter categorySchemeWriter = createCategorySchemeWriter(); + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + Xml21StructureWriter xmlStructureWriter = new Xml21StructureWriter( + actual, + List.of(categorySchemeWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + CategorySchemeImpl categoryScheme = MaintainableArtifactsTestUtils.buildCategoryScheme(); + artefacts.getCategorySchemes().add(categoryScheme); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(TestUtils.CATEGORY_SCHEME_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + + sdmxSourceCompatibilityTester.test(actual.toString(), SdmxBeans::getCategorySchemes); + } +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/CodelistWriterTest.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/CodelistWriterTest.java new file mode 100644 index 0000000..7e4ad67 --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/CodelistWriterTest.java @@ -0,0 +1,57 @@ +package com.epam.jsdmx.xml21.structure.writer; + + +import static com.epam.jsdmx.xml21.structure.TestUtils.CODELIST_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.xml21.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; +import org.xml.sax.SAXException; + +class CodelistWriterTest extends BaseXmlWriterTest { + + @Test + void writeCodelist() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + CodelistWriter codeListWriter = createCodelistWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + Xml21StructureWriter xmlStructureWriter = new Xml21StructureWriter( + actual, + List.of(codeListWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + CodelistImpl codelist = MaintainableArtifactsTestUtils.buildCodeList(); + artefacts.getCodelists().add(codelist); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(CODELIST_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + + final String actualString = actual.toString(); + assertXMLEqual(expected, actualString); + + sdmxSourceCompatibilityTester.test(actualString, SdmxBeans::getCodelists); + } +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/ConceptSchemeWriterTest.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/ConceptSchemeWriterTest.java new file mode 100644 index 0000000..47f36cb --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/ConceptSchemeWriterTest.java @@ -0,0 +1,57 @@ +package com.epam.jsdmx.xml21.structure.writer; + + +import static com.epam.jsdmx.xml21.structure.TestUtils.CONCEPT_SCHEME_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.xml21.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; +import org.xml.sax.SAXException; + +class ConceptSchemeWriterTest extends BaseXmlWriterTest { + + @Test + void writeConceptScheme() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + ConceptSchemeWriter conceptSchemeWriter = createConceptSchemeWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + Xml21StructureWriter xmlStructureWriter = new Xml21StructureWriter( + actual, + List.of(conceptSchemeWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + ConceptSchemeImpl conceptScheme = MaintainableArtifactsTestUtils.buildConceptScheme(); + artefacts.getConceptSchemes().add(conceptScheme); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(CONCEPT_SCHEME_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + final String actualString = actual.toString(); + assertXMLEqual(expected, actualString); + + sdmxSourceCompatibilityTester.test(actualString, SdmxBeans::getConceptSchemes); + } +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/ContentConstraintWriterTest.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/ContentConstraintWriterTest.java new file mode 100644 index 0000000..b2698ea --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/ContentConstraintWriterTest.java @@ -0,0 +1,93 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static com.epam.jsdmx.xml21.structure.TestUtils.DATA_CONSTRAINTS_XML; +import static com.epam.jsdmx.xml21.structure.TestUtils.META_DATA_CONSTRAINTS_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataConstraint; +import com.epam.jsdmx.xml21.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; +import org.xml.sax.SAXException; + +public class ContentConstraintWriterTest extends BaseXmlWriterTest { + + @Test + void writeContentConstraint() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + ContentConstraintWriter writer = createContentConstraintWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + Xml21StructureWriter xmlStructureWriter = + new Xml21StructureWriter( + actual, + List.of(writer), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + DataConstraintImpl dataConstraint = MaintainableArtifactsTestUtils.buildDataConstraint(); + artefacts.getDataConstraints().add(dataConstraint); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(DATA_CONSTRAINTS_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + final String actualString = actual.toString(); + assertXMLEqual(expected, actualString); + + sdmxSourceCompatibilityTester.test(expected, SdmxBeans::getContentConstraintBeans); + } + + @Test + void writeContentConstraintWithMeta() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + ContentConstraintWriter writer = createContentConstraintWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + Xml21StructureWriter xmlStructureWriter = + new Xml21StructureWriter( + actual, + List.of(writer), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + MetadataConstraint constraint = MaintainableArtifactsTestUtils.buildMetadataConstraint(false); + artefacts.getMetadataConstraints().add(constraint); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(META_DATA_CONSTRAINTS_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + final String actualString = actual.toString(); + assertXMLEqual(expected, actualString); + + sdmxSourceCompatibilityTester.test(actualString, SdmxBeans::getContentConstraintBeans); + } + +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataConsumerSchemeWriterTest.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataConsumerSchemeWriterTest.java new file mode 100644 index 0000000..8f8233d --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataConsumerSchemeWriterTest.java @@ -0,0 +1,57 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerSchemeImpl; +import com.epam.jsdmx.xml21.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml21.structure.TestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; +import org.xml.sax.SAXException; + +class DataConsumerSchemeWriterTest extends BaseXmlWriterTest { + + @Test + void writeDataConsumerScheme() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + OrganisationSchemeWriter dataConsumerSchemeWriter = createOrganisationSchemeWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + Xml21StructureWriter xmlStructureWriter = new Xml21StructureWriter( + actual, + List.of(dataConsumerSchemeWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + DataConsumerSchemeImpl consumerScheme = MaintainableArtifactsTestUtils.buildDataConsumerScheme(); + artefacts.getDataConsumerSchemes().add(consumerScheme); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(TestUtils.DATA_CONSUMER_SCHEME_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + final String actualString = actual.toString(); + assertXMLEqual(expected, actualString); + + sdmxSourceCompatibilityTester.test(actualString, SdmxBeans::getDataConsumerSchemes); + } + +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataProviderSchemeWriterTest.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataProviderSchemeWriterTest.java new file mode 100644 index 0000000..443390a --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataProviderSchemeWriterTest.java @@ -0,0 +1,57 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderSchemeImpl; +import com.epam.jsdmx.xml21.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml21.structure.TestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; +import org.xml.sax.SAXException; + +class DataProviderSchemeWriterTest extends BaseXmlWriterTest { + + @Test + void writeDataProviderScheme() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + OrganisationSchemeWriter dataProviderSchemeWriter = createOrganisationSchemeWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + Xml21StructureWriter xmlStructureWriter = new Xml21StructureWriter( + actual, + List.of(dataProviderSchemeWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + DataProviderSchemeImpl dataProviderScheme = MaintainableArtifactsTestUtils.buildDataProviderScheme(); + artefacts.getDataProviderSchemes().add(dataProviderScheme); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(TestUtils.DATA_PROVIDER_SCHEME_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + final String actualString = actual.toString(); + assertXMLEqual(expected, actualString); + + sdmxSourceCompatibilityTester.test(actualString, SdmxBeans::getDataProviderSchemes); + } + +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataStructureDefinitionWriterTest.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataStructureDefinitionWriterTest.java new file mode 100644 index 0000000..91e6568 --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataStructureDefinitionWriterTest.java @@ -0,0 +1,63 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeRef; +import com.epam.jsdmx.xml21.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml21.structure.TestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; +import org.xml.sax.SAXException; + +class DataStructureDefinitionWriterTest extends BaseXmlWriterTest { + + @Test + void writeDsd() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + DataStructureDefinitionWriter dataStructureDefinitionWriter = createDataStructureDefinitionWriter(); + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + Xml21StructureWriter xmlStructureWriter = new Xml21StructureWriter( + actual, + List.of(dataStructureDefinitionWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + DataStructureDefinitionImpl dataStructureDefinition = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + dataStructureDefinition.setAttributeDescriptor(MaintainableArtifactsTestUtils.fillAttributeDescriptor()); + dataStructureDefinition.setDimensionDescriptor(MaintainableArtifactsTestUtils.fillDimensionDescriptor()); + dataStructureDefinition.setMeasureDescriptor(MaintainableArtifactsTestUtils.fillMeasureDescriptor()); + dataStructureDefinition.setGroupDimensionDescriptor(MaintainableArtifactsTestUtils.fillListGroupDimensionDescriptor()); + + List attributeRefs = dataStructureDefinition.getAttributeDescriptor().getMetadataAttributes(); + List refs = List.of(attributeRefs.get(0), attributeRefs.get(1)); + dataStructureDefinition.getAttributeDescriptor().setMetadataAttributes(refs); + InputStream resourceAsStream = this.getClass().getResourceAsStream(TestUtils.DSD_XML); + artefacts.getDataStructures().add(dataStructureDefinition); + xmlStructureWriter.write(artefacts); + + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + final String actualString = actual.toString(); + assertXMLEqual(expected, actualString); + + sdmxSourceCompatibilityTester.test(actualString, SdmxBeans::getDataStructures); + } +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataflowWriterTest.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataflowWriterTest.java new file mode 100644 index 0000000..eee265d --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/DataflowWriterTest.java @@ -0,0 +1,56 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static com.epam.jsdmx.xml21.structure.TestUtils.DATAFLOW_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.xml21.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; +import org.xml.sax.SAXException; + +class DataflowWriterTest extends BaseXmlWriterTest { + + @Test + void writeDataflow() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + DataflowWriter dataflowWriter = createDataflowWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + Xml21StructureWriter xmlStructureWriter = new Xml21StructureWriter( + actual, + List.of(dataflowWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + DataflowImpl dataflow = MaintainableArtifactsTestUtils.buildDataFlow(); + artefacts.getDataflows().add(dataflow); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(DATAFLOW_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + final String actualString = actual.toString(); + assertXMLEqual(expected, actualString); + + sdmxSourceCompatibilityTester.test(actualString, SdmxBeans::getDataflows); + } +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/HierarchicalCodelistWriterTest.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/HierarchicalCodelistWriterTest.java new file mode 100644 index 0000000..f6dab28 --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/HierarchicalCodelistWriterTest.java @@ -0,0 +1,90 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static com.epam.jsdmx.xml21.structure.TestUtils.HIERARCHIES_NAMES_XML; +import static com.epam.jsdmx.xml21.structure.TestUtils.HIERARCHIES_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.xml21.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; +import org.xml.sax.SAXException; + +class HierarchicalCodelistWriterTest extends BaseXmlWriterTest { + + @Test + void writeHierarchy() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + HierarchicalCodelistWriter hierarchyWriter = createHierarchyWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + Xml21StructureWriter xmlStructureWriter = + new Xml21StructureWriter( + actual, + List.of(hierarchyWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + HierarchyImpl hierarchy = MaintainableArtifactsTestUtils.buildHierarchy(); + artefacts.getHierarchies().add(hierarchy); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(HIERARCHIES_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + final String actualString = actual.toString(); + assertXMLEqual(expected, actualString); + + sdmxSourceCompatibilityTester.test(actualString, SdmxBeans::getHierarchicalCodelists); + } + + @Test + void writeHierarchyWithNull() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + HierarchicalCodelistWriter hierarchyWriter = createHierarchyWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + Xml21StructureWriter xmlStructureWriter = + new Xml21StructureWriter(actual, List.of(hierarchyWriter), new HeaderWriter(defaultHeaderProvider), false); + + //when + Artefacts artefacts = new ArtefactsImpl(); + HierarchyImpl hierarchy = MaintainableArtifactsTestUtils.buildHierarchy(); + InternationalString name = hierarchy.getName(); + name.add("it", null); + artefacts.getHierarchies().add(hierarchy); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(HIERARCHIES_NAMES_XML); + System.out.println(actual); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + final String actualString = actual.toString(); + assertXMLEqual(expected, actualString); + + sdmxSourceCompatibilityTester.test(actualString, SdmxBeans::getHierarchicalCodelists); + } +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/OrganisationSchemeWriterTest.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/OrganisationSchemeWriterTest.java new file mode 100644 index 0000000..87392de --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/OrganisationSchemeWriterTest.java @@ -0,0 +1,55 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static com.epam.jsdmx.xml21.structure.MaintainableArtifactsTestUtils.buildAgencyScheme; +import static com.epam.jsdmx.xml21.structure.TestUtils.AGENCY_SCHEME_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.AgencySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.sdmxsource.sdmx.api.model.beans.SdmxBeans; +import org.xml.sax.SAXException; + +class OrganisationSchemeWriterTest extends BaseXmlWriterTest { + + @Test + void writeAgencyScheme() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + OrganisationSchemeWriter organisationSchemeWriter = createOrganisationSchemeWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + Xml21StructureWriter xmlStructureWriter = new Xml21StructureWriter( + actual, + List.of(organisationSchemeWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + AgencySchemeImpl agencyScheme = buildAgencyScheme(); + artefacts.getAgencySchemes().add(agencyScheme); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(AGENCY_SCHEME_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + + sdmxSourceCompatibilityTester.test(actual.toString(), SdmxBeans::getAgenciesSchemes); + } +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/Xml21StructureWriterTest.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/Xml21StructureWriterTest.java new file mode 100644 index 0000000..881da71 --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/Xml21StructureWriterTest.java @@ -0,0 +1,101 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static com.epam.jsdmx.xml21.structure.TestUtils.ALL_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorisationImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategoryScheme; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureMapImpl; +import com.epam.jsdmx.xml21.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class Xml21StructureWriterTest extends BaseXmlWriterTest { + + @Test + void writeAll() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + // root elements + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + Xml21StructureWriter xmlStructureWriter = new Xml21StructureWriter( + actual, + List.of( + createCategorisationWriter(), + createConceptSchemeWriter(), + createCodelistWriter(), + createCategorySchemeWriter(), + createDataflowWriter(), + createDataStructureDefinitionWriter(), + createHierarchyWriter(), + createOrganisationSchemeWriter() + ), + headerWriter, + true + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + + ConceptSchemeImpl conceptScheme = MaintainableArtifactsTestUtils.buildConceptScheme(); + artefacts.getConceptSchemes().add(conceptScheme); + + CategoryScheme categoryScheme = MaintainableArtifactsTestUtils.buildCategoryScheme(); + artefacts.getCategorySchemes().add(categoryScheme); + + CategorisationImpl categorisation = MaintainableArtifactsTestUtils.buildCategorisation(); + artefacts.getCategorisations().add(categorisation); + + CodelistImpl codelist = MaintainableArtifactsTestUtils.buildCodeList(); + artefacts.getCodelists().add(codelist); + + DataflowImpl dataflow = MaintainableArtifactsTestUtils.buildDataFlow(); + artefacts.getDataflows().add(dataflow); + + MetadataflowImpl metadataflow = MaintainableArtifactsTestUtils.buildMetadataFlow(); + artefacts.getMetadataflows().add(metadataflow); + + DataStructureDefinitionImpl dataStructureDefinition = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + artefacts.getDataStructures().add(dataStructureDefinition); + + MetadataStructureDefinitionImpl metadataStructureDefinition = MaintainableArtifactsTestUtils.buildMetadataStructureDefinition(); + artefacts.getMetadataStructureDefinitions().add(metadataStructureDefinition); + + HierarchyImpl hierarchy = MaintainableArtifactsTestUtils.buildHierarchy(); + artefacts.getHierarchies().add(hierarchy); + + RepresentationMapImpl representationMap = MaintainableArtifactsTestUtils.buildRepresentationMap(); + artefacts.getRepresentationMaps().add(representationMap); + + StructureMapImpl structureMap = MaintainableArtifactsTestUtils.buildStructureMap(); + artefacts.getStructureMaps().add(structureMap); + + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(ALL_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/XsdToXmlTest.java b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/XsdToXmlTest.java new file mode 100644 index 0000000..f1788cd --- /dev/null +++ b/sdmx-ml21/src/test/java/com/epam/jsdmx/xml21/structure/writer/XsdToXmlTest.java @@ -0,0 +1,49 @@ +package com.epam.jsdmx.xml21.structure.writer; + +import static com.epam.jsdmx.xml21.structure.TestUtils.AGENCY_SCHEME_XML; +import static com.epam.jsdmx.xml21.structure.TestUtils.ALL_XML; +import static com.epam.jsdmx.xml21.structure.TestUtils.CATEGORISATION_XML; +import static com.epam.jsdmx.xml21.structure.TestUtils.CATEGORY_SCHEME_XML; +import static com.epam.jsdmx.xml21.structure.TestUtils.CODELIST_XML; +import static com.epam.jsdmx.xml21.structure.TestUtils.CONCEPT_SCHEME_XML; +import static com.epam.jsdmx.xml21.structure.TestUtils.DATAFLOW_XML; +import static com.epam.jsdmx.xml21.structure.TestUtils.DATA_CONSUMER_SCHEME_XML; +import static com.epam.jsdmx.xml21.structure.TestUtils.DATA_PROVIDER_SCHEME_XML; +import static com.epam.jsdmx.xml21.structure.TestUtils.DSD_XML; +import static com.epam.jsdmx.xml21.structure.TestUtils.HIERARCHIES_XML; +import static com.epam.jsdmx.xml21.structure.TestUtils.validateXMLSchema; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Objects; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.util.ResourceUtils; + +class XsdToXmlTest { + + public static final String XML_XSD_SCHEMAS_SDMXMESSAGE_XSD = "/xml/xsd/schemas/SDMXMessage.xsd"; + + @ParameterizedTest + @ValueSource(strings = { + CODELIST_XML, + HIERARCHIES_XML, + CONCEPT_SCHEME_XML, + CATEGORISATION_XML, + DSD_XML, + DATAFLOW_XML, + CATEGORY_SCHEME_XML, + AGENCY_SCHEME_XML, + DATA_CONSUMER_SCHEME_XML, + DATA_PROVIDER_SCHEME_XML, + CONCEPT_SCHEME_XML, + ALL_XML, + }) + void xmlToXsd(String path) throws FileNotFoundException { + File fileXsd = ResourceUtils.getFile(Objects.requireNonNull(this.getClass().getResource(XML_XSD_SCHEMAS_SDMXMESSAGE_XSD))); + File fileXml = ResourceUtils.getFile(Objects.requireNonNull(this.getClass().getResource(path))); + Assertions.assertTrue(validateXMLSchema(fileXsd, fileXml)); + } +} diff --git a/sdmx-ml21/src/test/resources/xml/agency-scheme.xml b/sdmx-ml21/src/test/resources/xml/agency-scheme.xml new file mode 100644 index 0000000..f831add --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/agency-scheme.xml @@ -0,0 +1,86 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + Agency + Agency + + AG_1 + IT + writing + ecrire + 9458673082 + somedatafax + X400 + test@email.com + + + AG_2 + IT + writing + ecrire + 9458673082 + somedatafax2 + X400 + test@email.com + + + + Agency + Agency + + AG_1 + IT + writing + ecrire + 9458673082 + somedatafax + X400 + test@email.com + + + AG_2 + IT + writing + ecrire + 9458673082 + somedatafax2 + X400 + test@email.com + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/all.xml b/sdmx-ml21/src/test/resources/xml/all.xml new file mode 100644 index 0000000..8b40079 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/all.xml @@ -0,0 +1,212 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + Category1 + description category 1 + + + + + + Category2 + description category2 + + + Category3 + description category3 + + + + Category4 + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + code 1 + code 1 desc + + + + + + code 2 + code 2 desc + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + Maintanable artefact + artefact + + + + + + + + + + + + + + + + + + + + + hierarchy name + hierarchy desc + + + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + Country + + + + + QHB + Schema + Conn + + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/categorisation.xml b/sdmx-ml21/src/test/resources/xml/categorisation.xml new file mode 100644 index 0000000..a682c21 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/categorisation.xml @@ -0,0 +1,42 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/categorisation_with_hierarchy_ref.xml b/sdmx-ml21/src/test/resources/xml/categorisation_with_hierarchy_ref.xml new file mode 100644 index 0000000..5c63e66 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/categorisation_with_hierarchy_ref.xml @@ -0,0 +1,42 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/category-scheme-map.xml b/sdmx-ml21/src/test/resources/xml/category-scheme-map.xml new file mode 100644 index 0000000..243f7ca --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/category-scheme-map.xml @@ -0,0 +1,51 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:CatScheme(1.0) + urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:CatScheme(1.1) + + + + + S-1 + IM-1 + + + + + + S-2 + IM-2 + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/category-scheme.xml b/sdmx-ml21/src/test/resources/xml/category-scheme.xml new file mode 100644 index 0000000..c98f002 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/category-scheme.xml @@ -0,0 +1,57 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + Category1 + description category 1 + + + + + + Category2 + description category2 + + + Category3 + description category3 + + + + Category4 + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/codelist.xml b/sdmx-ml21/src/test/resources/xml/codelist.xml new file mode 100644 index 0000000..b58befb --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/codelist.xml @@ -0,0 +1,46 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + code 1 + code 1 desc + + + + + + code 2 + code 2 desc + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/concept-scheme-map.xml b/sdmx-ml21/src/test/resources/xml/concept-scheme-map.xml new file mode 100644 index 0000000..156f987 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/concept-scheme-map.xml @@ -0,0 +1,51 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ConScheme(1.0) + urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ConScheme(1.1) + + + + + S-1 + IM-1 + + + + + + S-2 + IM-2 + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/concept-scheme.xml b/sdmx-ml21/src/test/resources/xml/concept-scheme.xml new file mode 100644 index 0000000..6740586 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/concept-scheme.xml @@ -0,0 +1,47 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + Country + + + + + QHB + Schema + Conn + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/data-constraints.xml b/sdmx-ml21/src/test/resources/xml/data-constraints.xml new file mode 100644 index 0000000..9f82c9e --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/data-constraints.xml @@ -0,0 +1,70 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + + + Periodicity + Offset + Tolerance + + + + + Value + + + + + + + + + + 2020 + + + 2021 + + + + local + selectionValue1 + + + selectionValue2 + selectionValue5 + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/data-consumer-scheme.xml b/sdmx-ml21/src/test/resources/xml/data-consumer-scheme.xml new file mode 100644 index 0000000..7afb932 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/data-consumer-scheme.xml @@ -0,0 +1,59 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + Data Consumer + Data Consumer description + + AG_1 + IT + writing + ecrire + 9458673082 + somedatafax + X400 + test@email.com + + + AG_2 + IT + writing + ecrire + 9458673082 + somedatafax2 + X400 + test@email.com + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/data-provider-scheme.xml b/sdmx-ml21/src/test/resources/xml/data-provider-scheme.xml new file mode 100644 index 0000000..fb46888 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/data-provider-scheme.xml @@ -0,0 +1,63 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + Val + + + D_P + + AG_1 + IT + writing + ecrire + 9458673082 + somedatafax + X400 + test@email.com + + + AG_2 + IT + writing + ecrire + 9458673082 + somedatafax2 + X400 + test@email.com + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/dataflow.xml b/sdmx-ml21/src/test/resources/xml/dataflow.xml new file mode 100644 index 0000000..02fc05f --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/dataflow.xml @@ -0,0 +1,40 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/dsd.xml b/sdmx-ml21/src/test/resources/xml/dsd.xml new file mode 100644 index 0000000..cc1feaf --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/dsd.xml @@ -0,0 +1,127 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/geographical-codelist.xml b/sdmx-ml21/src/test/resources/xml/geographical-codelist.xml new file mode 100644 index 0000000..d2c07cf --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/geographical-codelist.xml @@ -0,0 +1,56 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + + Maintanable artefact + artefact + Some artefact + + code 1 + code 1 desc + CODE2 + + + code 2 + code 2 desc + + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1) + + mem1 + + + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1) + + mem2 + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/geogrid-codelist.xml b/sdmx-ml21/src/test/resources/xml/geogrid-codelist.xml new file mode 100644 index 0000000..e788426 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/geogrid-codelist.xml @@ -0,0 +1,58 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + + Maintanable artefact + artefact + Some artefact + + code 1 + code 1 desc + CODE2 + Value1 + + + code 2 + code 2 desc + Value2 + + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1) + + mem1 + + + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1) + + mem2 + + + DEFINITION + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/hierarchy.xml b/sdmx-ml21/src/test/resources/xml/hierarchy.xml new file mode 100644 index 0000000..7f17fb8 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/hierarchy.xml @@ -0,0 +1,67 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + Maintanable artefact + artefact + + + + + + + + + + + + + + + + + + + + + hierarchy name + hierarchy desc + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/hierarchy_names.xml b/sdmx-ml21/src/test/resources/xml/hierarchy_names.xml new file mode 100644 index 0000000..234e859 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/hierarchy_names.xml @@ -0,0 +1,69 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + + artefact + Some artefact + + Maintanable artefact + + artefact + + + + + + + + + + + + + + + + + + + + + hierarchy name + hierarchy desc + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/metadata-constraints.xml b/sdmx-ml21/src/test/resources/xml/metadata-constraints.xml new file mode 100644 index 0000000..79808a5 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/metadata-constraints.xml @@ -0,0 +1,53 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + + + Periodicity + Offset + Tolerance + + + + MEM + local + + + + 2023 + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/metadata-provider-scheme.xml b/sdmx-ml21/src/test/resources/xml/metadata-provider-scheme.xml new file mode 100644 index 0000000..ce32428 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/metadata-provider-scheme.xml @@ -0,0 +1,63 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + + Maintanable artefact + artefact + Some artefact + + + + Val + + + MD_P + + AG_1 + IT + writing + ecrire + 9458673082 + somedatafax + X400 + test@email.com + + + AG_2 + IT + writing + ecrire + 9458673082 + somedatafax2 + X400 + test@email.com + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/metadata-provision-agreement.xml b/sdmx-ml21/src/test/resources/xml/metadata-provision-agreement.xml new file mode 100644 index 0000000..b9c023d --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/metadata-provision-agreement.xml @@ -0,0 +1,37 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=IMF:ARTEFACT(1.2) + urn:sdmx:org.sdmx.infomodel.base.MetadataProvider=IMF:METADATA_PROVIDERS(1.0).PR + + + + diff --git a/sdmx-ml21/src/test/resources/xml/organisation-scheme-map.xml b/sdmx-ml21/src/test/resources/xml/organisation-scheme-map.xml new file mode 100644 index 0000000..048f3ab --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/organisation-scheme-map.xml @@ -0,0 +1,51 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.base.AgencyScheme=SDMX:AGENCIES(1.0) + urn:sdmx:org.sdmx.infomodel.base.AgencyScheme=SDMX:AGENCIES(1.0) + + + + + S-1 + IM-1 + + + + + + S-2 + IM-2 + + + + + diff --git a/sdmx-ml21/src/test/resources/xml/organisation-unit-scheme.xml b/sdmx-ml21/src/test/resources/xml/organisation-unit-scheme.xml new file mode 100644 index 0000000..d4a7c81 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/organisation-unit-scheme.xml @@ -0,0 +1,64 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + OrganisationUnit + OrganisationUnit description + + AG_1 + IT + writing + ecrire + 9458673082 + somedatafax + X400 + test@email.com + + + AG_2 + IT + writing + ecrire + 9458673082 + somedatafax2 + X400 + test@email.com + + + + OrganisationUnit + OrgUnit + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/process.xml b/sdmx-ml21/src/test/resources/xml/process.xml new file mode 100644 index 0000000..9b81013 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/process.xml @@ -0,0 +1,70 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + + Maintanable artefact + artefact + Some artefact + + + + + ProcessStep + ProcessStep description + + + + + urn:sdmx:org.sdmx.infomodel.process.ProcessStep=IMF:Artefact(1.0) + + + + + + urn:sdmx:org.sdmx.infomodel.process.ProcessStep=IMF:Artefact(1.0) + + + + + + Computation Description + + + ST + Doo + + + + + + ProcessStepChild + + + + + + diff --git a/sdmx-ml21/src/test/resources/xml/provision-agreement.xml b/sdmx-ml21/src/test/resources/xml/provision-agreement.xml new file mode 100644 index 0000000..737a02f --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/provision-agreement.xml @@ -0,0 +1,36 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=IMF:ARTEFACT(1.2) + urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP + + + + diff --git a/sdmx-ml21/src/test/resources/xml/reporting-taxonomy-map.xml b/sdmx-ml21/src/test/resources/xml/reporting-taxonomy-map.xml new file mode 100644 index 0000000..5f4e095 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/reporting-taxonomy-map.xml @@ -0,0 +1,51 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.categoryscheme.ReportingTaxonomy=SDMX:REP_SOURCE(1.0) + urn:sdmx:org.sdmx.infomodel.categoryscheme.ReportingTaxonomy=SDMX:REP_TARGET(1.0) + + + + + S-1 + IM-1 + + + + + + S-2 + IM-2 + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/reporting-taxonomy.xml b/sdmx-ml21/src/test/resources/xml/reporting-taxonomy.xml new file mode 100644 index 0000000..c84dd9d --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/reporting-taxonomy.xml @@ -0,0 +1,61 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + ReportingCat + ReportingCat description + + + + + ReportingCat2 + ReportingCat2 description + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=EPM:DataS2(3.0) + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=EPM:DataS1(3.0) + + + + urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataS2(3.0) + + + urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataS1(3.0) + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/representation_map.xml b/sdmx-ml21/src/test/resources/xml/representation_map.xml new file mode 100644 index 0000000..6f9dad8 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/representation_map.xml @@ -0,0 +1,42 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_SOURCE(1.0) + DateTime + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_TARGET(1.0) + + mappedValue + targetValue1 + targetValue2 + + + + + diff --git a/sdmx-ml21/src/test/resources/xml/structure_map.xml b/sdmx-ml21/src/test/resources/xml/structure_map.xml new file mode 100644 index 0000000..8e0a4b6 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/structure_map.xml @@ -0,0 +1,70 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0) + urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0) + + CompMapEpochS + CompMapEpochT + Frequency_dim + FR3 + + + CompMapDPS + CompMapDPT + Frequency_dim + FR1 + FR2 + + + CODE_3 + 2022-11 + + + CODE_1 + 2022-11 + + + CODE_2 + 2022-11 + + + CompMapRepS + CompMapRepT + urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2) + + + STRUC_ID + value + + + + + diff --git a/sdmx-ml21/src/test/resources/xml/valuelist.xml b/sdmx-ml21/src/test/resources/xml/valuelist.xml new file mode 100644 index 0000000..9e2cac2 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/valuelist.xml @@ -0,0 +1,50 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + + Maintanable artefact + artefact + Some artefact + + + + + value + val + it is value + c'est val + + + + + + smth + smth description + + + + + diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXCommon.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXCommon.xsd new file mode 100644 index 0000000..a6bcd20 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXCommon.xsd @@ -0,0 +1,1733 @@ + + + + + + + + + SDMX Common Namespace Module + The common namespace module contains common constructs that are used by constructs in other namespaces. + + + + + TextType provides for a set of language-specific alternates to be provided for any human-readable constructs in the instance. + + + + + + The xml:lang attribute specifies a language code for the text. If not supplied, the default language is assumed to be English. + + + + + + + + + Name is a reusable element, used for providing a human-readable name for an object. + + + + + + Description is a reusable element, used for providing a longer human-readable description of an object. + + + + + + Text is a reusable element, used for providing a language specific text value for general purposes (i.e. not for a name or description). + + + + + + StructuredText is a reusable element, used for providing a language specific text value structured as XHTML. + + + + + + StatusMessageType describes the structure of an error or warning message. A message contains the text of the message, as well as an optional language indicator and an optional code. + + + + + Text contains the text of the message, in parallel language values. + + + + + + The code attribute holds an optional code identifying the underlying error that generated the message. This should be used if parallel language descriptions of the error are supplied, to distinguish which of the multiple error messages are for the same underlying error. + + + + + + + CodedStatusMessageType describes the structure of an error or warning message which required a code. + + + + + + + + + + + + + + AnnotableType is an abstract base type used for all annotable artefacts. Any type that provides for annotations should extend this type. + + + + + + + + + Annotations is a reusable element the provides for a collection of annotations. It has been made global so that restrictions of types that extend AnnotatableType may reference it. + + + + + + AnnotationsType provides for a list of annotations to be attached to data and structure messages. + + + + + + + + + AnnotationType provides for non-documentation notes and annotations to be embedded in data and structure messages. It provides optional fields for providing a title, a type description, a URI, and the text of the annotation. + + + + + AnnotationTitle provides a title for the annotation. + + + + + AnnotationType is used to distinguish between annotations designed to support various uses. The types are not enumerated, as these can be specified by the user or creator of the annotations. The definitions and use of annotation types should be documented by their creator. + + + + + AnnotationURL is a URI - typically a URL - which points to an external resource which may contain or supplement the annotation. If a specific behavior is desired, an annotation type should be defined which specifies the use of this field more exactly. + + + + + AnnotationText holds a language-specific string containing the text of the annotation. + + + + + + The id attribute provides a non-standard identification of an annotation. It can be used to disambiguate annotations. + + + + + + + The SetAttributeGroup defines a common set of attributes for use in data and reference metadata sets. + + + + The structureRef contains a reference to a structural specification in the header of a data or reference metadata message. The structural specification details which structure the data or reference metadata conforms to, as well as providing additional information such as how the data is structure (e.g. which dimension occurs at the observation level for a data set). + + + + + The setID provides an identification of the data or metadata set. + + + + + The action attribute indicates whether the file is appending, replacing, or deleting. + + + + + The reportingBeginDate indicates the inclusive start time of the data reported in the data or metadata set. + + + + + The reportingEndDate indicates the inclusive end time of the data reported in the data or metadata set. + + + + + The validFromDate indicates the inclusive start time indicating the validity of the information in the data or metadata set. + + + + + The validToDate indicates the inclusive end time indicating the validity of the information in the data or metadata set. + + + + + The publicationYear holds the ISO 8601 four-digit year. + + + + + The publicationPeriod specifies the period of publication of the data or metadata in terms of whatever provisioning agreements might be in force (i.e., "Q1 2005" if that is the time of publication for a data set published on a quarterly basis). + + + + + + + + The serviceURL attribute indicates the URL of an SDMX SOAP web service from which the details of the object can be retrieved. Note that this can be a registry or and SDMX structural metadata repository, as they both implement that same web service interface. + + + + + The structureURL attribute indicates the URL of a SDMX-ML structure message (in the same version as the source document) in which the externally referenced object is contained. Note that this may be a URL of an SDMX RESTful web service which will return the referenced object. + + + + + + + AlphaNumericType is a reusable simple type that allows for only mixed-case alphabetical and numeric characters. + + + + + + + + + AlphaType is a reusable simple type that allows for only mixed-case alphabetical characters. This is derived from the AlphaNumericType. + + + + + + + + + NumericType is a reusable simple type that allows for only numeric characters. This is not to be confused with an integer, as this may be used to numeric strings which have leading zeros. These leading zeros are not ignored. This is derived from the AlphaNumericType. + + + + + + + + + ObservationalTimePeriodType specifies a distinct time period or point in time in SDMX. The time period can either be a Gregorian calendar period, a standard reporting period, a distinct point in time, or a time range with a specific date and duration. + + + + + + + StandardTimePeriodType defines the set of standard time periods in SDMX. This includes the reporting time periods and the basic date type (i.e. the calendar time periods and the dateTime format). + + + + + + + BasicTimePeriodType contains the basic dates and calendar periods. It is a combination of the Gregorian time periods and the date time type.. + + + + + + + GregorianTimePeriodType defines the set of standard calendar periods in SDMX. + + + + + + + ReportingTimePeriodType defines standard reporting periods in SDMX, which are all in relation to the start day (day-month) of a reporting year which is specified in the specialized reporting year start day attribute. If the reporting year start day is not defined, a day of January 1 is assumed. The reporting year must be epxressed as the year at the beginning of the period. Therfore, if the reproting year runs from April to March, any given reporting year is expressed as the year for April. The general format of a report period can be described as [year]-[period][time zone]?, where the type of period is designated with a single character followed by a number representing the period. Note that all periods allow for an optional time zone offset. See the details of each member type for the specifics of its format. + + + + + + + BaseReportPeriodType is a simple type which frames the general pattern of a reporting period for validation purposes. This regular expression is only a general validation which is meant to validate the following structure [year]-[period][time zone]?. This type is meant to be derived from for further validation. + + + + + + + + + ReportPeriodValidTimeZoneType is a derivation of the BaseReportPeriodType which validates that the time zone provided in the base type is valid. The base type will have provided basic validation already. The patterns below validate that the time zone is "Z" or that it is between -14:00 and +14:00, or that there is no time zone provided. This type is meant to be derived from for further validation. + + + + + + + + + + + ReportingYearType defines a time period of 1 year (P1Y) in relation to a reporting year which has a start day (day-month) specified in the specialized reporting year start day attribute. In the absence of a start day for the reporting year, a day of January 1 is assumed. In this case a reporting year will coincide with a calendar year. The format of a reporting year is YYYY-A1 (e.g. 2000-A1). Note that the period value of 1 is fixed. + + + + + + + + + ReportingSemesterType defines a time period of 6 months (P6M) in relation to a reporting year which has a start day (day-month) specified in the specialized reporting year start day attribute. In the absence of a start day for the reporting year, a day of January 1 is assumed. The format of a reporting semester is YYYY-Ss (e.g. 2000-S1), where s is either 1 or 2. + + + + + + + + + ReportingTrimesterType defines a time period of 4 months (P4M) in relation to a reporting year which has a start day (day-month) specified in the specialized reporting year start day attribute. In the absence of a start day for the reporting year, a day of January 1 is assumed. The format of a reporting trimester is YYYY-Tt (e.g. 2000-T1), where s is either 1, 2, or 3. + + + + + + + + + ReportingQuarterType defines a time period of 3 months (P3M) in relation to a reporting year which has a start day (day-month) specified in the specialized reporting year start day attribute. In the absence of a start day for the reporting year, a day of January 1 is assumed. The format of a reporting quarter is YYYY-Qq (e.g. 2000-Q1), where q is a value between 1 and 4. + + + + + + + + + ReportingMonthType defines a time period of 1 month (P1M) in relation to a reporting year which has a start day (day-month) specified in the specialized reporting year start day attribute. In the absence of a start day for the reporting year, a day of January 1 is assumed. In this case a reporting month will coincide with a calendar month. The format of a reporting month is YYYY-Mmm (e.g. 2000-M01), where mm is a two digit month (i.e. 01-12). + + + + + + + + + ReportingWeekType defines a time period of 7 days (P7D) in relation to a reporting year which has a start day (day-month) specified in the specialized reporting year start day attribute. A standard reporting week is based on the ISO 8601 defintion of a week date, in relation to the reporting period start day. The first week is defined as the week with the first Thursday on or after the reporting year start day. An equivalent definition is the week starting with the Monday nearest in time to the reporting year start day. There are other equivalent defintions, all of which should be adjusted based on the reporting year start day. In the absence of a start day for the reporting year, a day of January 1 is assumed. The format of a reporting week is YYYY-Www (e.g. 2000-W01), where mm is a two digit week (i.e. 01-53). + + + + + + + + + ReportingDayType defines a time period of 1 day (P1D) in relation to a reporting year which has a start day (day-month) specified in the specialized reporting year start day attribute. In the absence of a start day for the reporting year, a day of January 1 is assumed. The format of a reporting day is YYYY-Dddd (e.g. 2000-D001), where ddd is a three digit day (i.e. 001-366). + + + + + + + + + BaseTimeRangeType is a simple type which frames the general pattern for a time range in SDMX. A time range pattern is generally described as [xs:date or xs:dateTime]\[xs:duration], where the referenced types are defined by XML Schema. This type is meant to be derived from for further validation. + + + + + + + + + RangeValidMonthDayType is a derivation of the BaseTimeRangeType which validates that the day provided is valid for the month, without regard to leap years. The base type will have provided basic validation already. The patterns below validate that there are up to 29 days in February, up to 30 days in April, June, September, and November and up to 31 days in January, March, May, July, August, October, and December. This type is meant to be derived from for further validation. + + + + + + + + + + + RangeValidLeapYearType is a derivation of the RangeValidMonthDayType which validates that a date of February 29 occurs in a valid leap year (i.e. if the year is divisible 4 and not by 100, unless it is also divisible by 400). This type is meant to be derived from for further validation. + + + + + + + + + + + RangeValidTimeType is a derivation of the RangeValidLeapYearType which validates that the time (if provided) is validly formatted. The base type will have provided basic validation already. The patterns below validate that the time falls between 00:00:00 and 24:00:00. Note that as the XML dateTime type does, seconds are required. It is also permissible to have fractions of seconds, but only within the boundaries of the range specified. This type is meant to be derived from for further validation. + + + + + + + + + + RangeValidMonthDayType is a derivation of the RangeValidTimeType which validates that the time zone provided in the base type is valid. The base type will have provided basic validation already. The patterns below validate that the time zone is "Z" or that it is between -14:00 and +14:00, or that there is no time zone provided. This type is meant to be derived from for further validation. + + + + + + + + + + + TimeRangeValidDateDurationType is an abstract derivation of the RangeValidTimeType which validates that duration provided is generally valid, up to the time component. + + + + + + + + + TimeRangeType defines the structure of a time range in SDMX. The pattern of a time range can be generally described as [start date]\[duration], where start date is an date or dateTime type as defined in XML Schema and duration is a time duration as defined in XML Schema. Note that it is permissible for a time zone offset to be provided on the date or date time. + + + + + + + + + + TimezoneType defines the pattern for a time zone. An offset of -14:00 to +14:00 or Z can be specified. + + + + + + + + + + Specifies the inclusive start and end times. + + + + The startTime attributes contains the inclusive start date for the reference period. + + + + + The endTime attributes contains the inclusive end date for the reference period. + + + + + + + OccurenceType is used to express the maximum occurrence of an object. It combines an integer, greater than 1, and the literal text, "unbounded", for objects which have no upper limit on its occurrence. + + + + + + + MaxOccursNumberType is a base type used to restrict an integer to be greater than 1, for the purpose of expressing the maximum number of occurrences of an object. + + + + + + + + + UnboundedCodeType provides single textual value of "unbounded", for use in OccurentType. + + + + + Object has no upper limit on occurrences. + + + + + + + + ActionType provides a list of actions, describing the intention of the data transmission from the sender's side. Each action provided at the data or metadata set level applies to the entire data set for which it is given. Note that the actions indicated in the Message Header are optional, and used to summarize specific actions indicated with this data type for all registry interactions. The "Informational" value is used when the message contains information in response to a query, rather than being used to invoke a maintenance activity. + + + + + Append - this is an incremental update for an existing data/metadata set or the provision of new data or documentation (attribute values) formerly absent. If any of the supplied data or metadata is already present, it will not replace that data or metadata. This corresponds to the "Update" value found in version 1.0 of the SDMX Technical Standards. + + + + + Replace - data/metadata is to be replaced, and may also include additional data/metadata to be appended. The replacement occurs at the level of the observation - that is, it is not possible to replace an entire series. + + + + + Delete - data/metadata is to be deleted. Deletion occurs at the lowest level object. For instance, if a delete data message contains a series with no observations, then the entire series will be deleted. If the series contains observations, then only those observations specified will be deleted. The same basic concept applies for attributes. If a series or observation in a delete message contains attributes, then only those attributes will be deleted. + + + + + Informational - data/metadata is being exchanged for informational purposes only, and not meant to update a system. + + + + + + + + WildCardValueType is a single value code list, used to include the '%' character - indicating that an entire field is wild carded. + + + + + Indicates a wild card value. + + + + + + + + QueryableDataSourceType describes a data source which is accepts an standard SDMX Query message and responds appropriately. + + + + + DataURL contains the URL of the data source. + + + + + WSDLURL provides the location of a WSDL instance on the internet which describes the queryable data source. + + + + + WADLURL provides the location of a WADL instance on the internet which describes the REST protocol of the queryable data source. + + + + + + The isRESTDatasource attribute indicates, if true, that the queryable data source is accessible via the REST protocol. + + + + + The isWebServiceDatasource attribute indicates, if true, that the queryable data source is accessible via Web Services protocols. + + + + + + + DimensionTypeType enumerates the sub-classes of a dimension. + + + + + An ordinary dimension. + + + + + A measure dimension. + + + + + The time dimension. + + + + + + + + XHTMLType allows for mixed content of text and XHTML tags. When using this type, one will have to provide a reference to the XHTML schema, since the processing of the tags within this type is strict, meaning that they are validated against the XHTML schema provided. + + + + + + + + + + ContentConstraintTypeCodeType defines a list of types for a content constraint. A content constraint can state which data is present or which content is allowed for the constraint attachment. + + + + + The constraint contains the allowed values for attachable object. + + + + + The constraints contains the actual data present for the attachable object. + + + + + + + + RegionType is an abstract type which defines a generic constraint region. This type can be refined to define regions for data or metadata sets. A region is defined by a collection of key values - each of which a collection of values for a component which disambiguates data or metadata (i.e. dimensions or the target objects of a metadata target). For each region, as collection of attribute values can be provided. Taken together, the key values and attributes serve to identify or describe a subset of a data or metadata set. Finally, the region can flagged as being included or excluded, although this flag only makes sense when the region is used in a particular context. + + + + + KeyValue contains a reference to a component which disambiguates the data or metadata (i.e. a dimension or target object) and provides a collection of values for the component. The collection of values can be flagged as being inclusive or exclusive to the region being defined. Any key component that is not included is assumed to be wild carded, which is to say that the cube includes all possible values for the un-referenced key components. Further, this assumption applies to the values of the components as well. The values for any given component can only be sub-setted in the region by explicit inclusion or exclusion. For example, a dimension X which has the possible values of 1, 2, 3 is assumed to have all of these values if a key value is not defined. If a key value is defined with an inclusion attribute of true and the values of 1 and 2, the only the values of 1 and 2 for dimension X are included in the definition of the region. If the key value is defined with an inclusion attribute of false and the value of 1, then the values of 2 and 3 for dimension X are included in the definition of the region. Note that any given key component must only be referenced once in the region. + + + + + Attributes contains a reference to an attribute component (data or metadata) and provides a collection of values for the referenced attribute. This serves to state that for the key which defines the region, the attributes that are specified here have or do not have (depending to the include attribute of the value set) the values provided. It is possible to provide and attribute reference without specifying values, for the purpose of stating the attribute is absent (include = false) or present with an unbounded set of values. As opposed to key components, which are assumed to be wild carded if absent, no assumptions are made about the absence of an attribute. Only attributes which are explicitly stated to be present or absent from the region will be know. All unstated attributes for the set cannot be assumed to absent or present. + + + + + + The include attribute indicates that the region is to be included or excluded within the context in which it is defined. For example, if the regions is defined as part of a content constraint, the exclude flag would mean the data identified by the region is not present. + + + + + + + + ComponentValueSetType is an abstract base type which is used to provide a set of value for a referenced component. Implementations of this type will be based on a particular component type and refine the allowed values to reflect the types of values that are possible for that type of component. + + + + + Value provides a simple value for the component, such as a coded, numeric, or simple text value. This type of component value is applicable for dimensions and attributes. + + + + + DataSet provides a reference to a data set and is used to state a value for the data set target component in a metadata target. + + + + + DataKey provides a set of dimension references and value, which form a full or partial data key. This is used to state a value for the key descriptor values target component in a metadata target. + + + + + Object provides a reference to an Identifiable object in the SDMX Information Model. This is used to state a value for an identifiable target component in a metadata target. + + + + + TimeValue provides a value for a component which has a time representation. This is repeatable to allow for a range to be specified, although a single value can also be provided. An operator is available on this to indicate whether the specified value indicates an exact value or the beginning/end of a range (inclusive or exclusive). + + + + + + The id attribute provides the identifier for the component for which values are being provided. This base type allows for a nested identifier to be provided, for the purpose of referencing a nested component (i.e. a metadata attribute). However, specific implementations will restrict this representation to only allow single level identifiers where appropriate. + + + + + The include attribute indicates whether the values provided for the referenced component are to be included are excluded from the region in which they are defined. + + + + + + + DistinctKeyType is an abstract base type which is a special type of region that only defines a distinct region of data or metadata. For each component defined in the region, only a single values is provided. However, the same rules that apply to the general region about unstated components being wild carded apply here as well. Thus, this type can define a distinct full or partial key for data or metadata. + + + + + + + + + The include attribute has a fixed value of true for a distinct key, since such a key is always assumed to identify existing data or metadata. + + + + + + + + + + DinstinctKeyValueType is an abstract base type which defines a singular, required value for a key component. + + + + + + + + + + + + + + + + + + DataKeyType is a region which defines a distinct full or partial data key. The key consists of a set of values, each referencing a dimension and providing a single value for that dimension. The purpose of the key is to define a subset of a data set (i.e. the observed value and data attribute) which have the dimension values provided in this definition. Any dimension not stated explicitly in this key is assumed to be wild carded, thus allowing for the definition of partial data keys. + + + + + + + + + + + + + DataKeyValueType is a type for providing a dimension value for the purpose of defining a distinct data key. Only a single value can be provided for the dimension. + + + + + + + + + + + + + + MetadataKeyType is a region which defines a distinct full or partial metadata key. The key consists of a set of values, each referencing a target object for the metadata target referenced in the metadataTarget attribute, which must be defined in the report structure referenced in the report attribute. Each target object can be assigned a single value. If an target object from the reference metadata target is not included in this key, the value of that is assumed to be all known objects for a reference target object, all possible keys for a key descriptor values target object, or all dates for report period target object. The purpose of this key reference a metadata conforming to a particular report structure for given object or set of objects. + + + + + + + + + The report attribute is required and holds the identifier of the report structure which the reference metadata being defined by this key is based on. + + + + + The metadataTarget attribute is required and identifies the metadata target for the report structure which this key is based upon. Note that a report structure can have multiple metadata targets, so to properly determine the object or objects for which the key applies, the proper metadata target must be identified. + + + + + + + + + MetadataKeyValueType is a type for providing a target object value for the purpose of defining a distinct metadata key. Only a single value can be provided for the target object. + + + + + + + + + + + + + + + + + CubeRegionType defines the structure of a data cube region. This is based on the abstract RegionType and simply refines the key and attribute values to conform with what is applicable for dimensions and attributes, respectively. See the documentation of the base type for more details on how a region is defined. + + + + + + + + + + + + + + MetadataTargetRegionType defines the structure of a metadata target region. A metadata target region must define the report structure and the metadata target from that structure on which the region is based. This type is based on the abstract RegionType and simply refines the key and attribute values to conform with what is applicable for target objects and metadata attributes, respectively. See the documentation of the base type for more details on how a region is defined. + + + + + + + + + + The report attribute is required and holds the identifier of the report structure which the reference metadata being defined by this region is based on. + + + + + The metadataTarget attribute is required and identifies the metadata target for the report structure which this region is based upon. Note that a report structure can have multiple metadata targets, so to properly determine the object or objects for which the region applies, the proper metadata target must be identified. + + + + + + + + + CubeRegionKeyType is a type for providing a set of values for a dimension for the purpose of defining a data cube region. A set of distinct value can be provided, or if this dimension is represented as time, and time range can be specified. + + + + + + + + + + + + + + + MetadataTargetRegionKeyType is a type for providing a set of values for a target object in a metadata target of a re fence metadata report. A set of values or a time range can be provided for a report period target object. A collection of the respective types of references can be provided for data set reference and identifiable object reference target objects. For a key descriptor values target object, a collection of data keys can be provided. + + + + + + + + + + + + + + + + + + AttributeValueSetType defines the structure for providing values for a data attribute. If no values are provided, the attribute is implied to include/excluded from the region in which it is defined, with no regard to the value of the data attribute. Note that for metadata attributes which occur within other metadata attributes, a nested identifier can be provided. For example, a value of CONTACT.ADDRESS.STREET refers to the metadata attribute with the identifier STREET which exists in the ADDRESS metadata attribute in the CONTACT metadata attribute, which is defined at the root of the report structure. + + + + + + + + + + + + + + + MetadataAttributeValueSetType defines the structure for providing values for a metadata attribute. If no values are provided, the attribute is implied to include/excluded from the region in which it is defined, with no regard to the value of the metadata attribute. + + + + + + + + + + + + + + SimpleValueType contains a simple value for a component, and if that value is from a code list, the ability to indicate that child codes in a simple hierarchy are part of the value set of the component for the region. + + + + + + The cascadeValues attribute, if true, indicates that if the value is taken from a code all child codes in a simple hierarchy are understood be included in the region. + + + + + + + + + SimpleKeyValueType derives from the SimpleValueType, but does not allow for the cascading of value in the hierarchy, as keys are meant to describe a distinct full or partial key. + + + + + + + + + + + TimeRangeValueType allows a time period value to be expressed as a range. It can be expressed as the period before a period, after a period, or between two periods. Each of these properties can specify their inclusion in regards to the range. + + + + + BeforePeriod is the period before which the period is meant to cover. This date may be inclusive or exclusive in the range. + + + + + AfterPeriod is the period after which the period is meant to cover. This date may be inclusive or exclusive in the range. + + + + + + StartPeriod is the start date or the range that the queried date must occur within. This date may be inclusive or exclusive in the range. + + + + + EndPeriod is the end period of the range. This date may be inclusive or exclusive in the range. + + + + + + + + + TimePeriodRangeType defines a time period, and indicates whether it is inclusive in a range. + + + + + + The isInclusive attribute, when true, indicates that the time period specified is included in the range. + + + + + + + + + SimpleOperatorType provides an enumeration of simple operators to be applied to any value. + + + + + (!=) - value must not be equal to the value supplied. + + + + + (=) - value must be exactly equal to the value supplied. + + + + + + + + RangeOperatorType provides an enumeration of range operators to be applied to an ordered value. + + + + + (>=) - value must be greater than or equal to the value supplied. + + + + + (<=) - value must be less than or equal to the value supplied. + + + + + (>) - value must be greater than the value supplied. + + + + + (<) - value must be less than the value supplied. + + + + + + + + TextSearchOperatorType provides an enumeration of text search operators. + + + + + The text being searched must contain the supplied text. + + + + + The text being searched must start with the supplied text. + + + + + The text being searched must end with the supplied text. + + + + + The text being searched cannot contain the supplied text. + + + + + The text being searched cannot start with the supplied text. + + + + + The text being searched cannot end with the supplied text. + + + + + + + + OrderedOperatorType combines the SimpleOperatorType and the RangeOperatorType to provide a full range or operators for any ordered value. + + + + + + + + + + + + + + TimeOperatorType derives from the OrderedOperatorType to remove the notEqual operator. + + + + + + + + + + + + + + + PayloadStructureType is an abstract base type used to define the structural information for data or metadata sets. A reference to the structure is provided (either explicitly or through a reference to a structure usage). + + + + + + ProvisionAgreement references a provision agreement which the data or metadata is reported against. + + + + + StructureUsage references a flow which the data or metadata is reported against. + + + + + Structure references the structure which defines the structure of the data or metadata set. + + + + + + + The structureID attribute uniquely identifies the structure for the purpose of referencing it from the payload. This is only used in structure specific formats. Although it is required, it is only useful when more than one data set is present in the message. + + + + + The schemaURL attribute provides a location from which the structure specific schema can be located. + + + + + The namespace attribute is used to provide the namespace for structure-specific formats. By communicating this information in the header, it is possible to generate the structure specific schema while processing the message. + + + + + The dimensionAtObservation is used to reference the dimension at the observation level for data messages. This can also be given the explicit value of "AllDimensions" which denotes that the cross sectional data is in the flat format. + + + + + The explicitMeasures indicates whether explicit measures are used in the cross sectional format. This is only applicable for the measure dimension as the dimension at the observation level or the flat structure. + + + + + + + + DataStructureType is an abstract base type the forms the basis for the structural information for a data set. + + + + + + + + ProvisionAgreement references a provision agreement which the data is reported against. + + + + + StructureUsage references a dataflow which the data is reported against. + + + + + Structure references the data structure definition which defines the structure of the data. + + + + + + + + + + + DataStructureRequestType is a variation of a the DataStructureType for querying purposes. Only the observation dimension and the explicit measures flag are allowed. + + + + + + + + + + + + + + + + + + + + + GenericDataStructureRequestType is a variation of a the DataStructureRequestType for querying purposes. The explicit measure flag in not allowed. + + + + + + + + + + + + + + + + + + + TimeSeriesDataStructureRequestType is a variation of a the DataStructureRequestType for querying purposes. The observation dimension is fixed to TIME_PERIOD + + + + + + + + + + + + + + + + + + + TimeSeriesGenericDataStructureRequestType is a variation of a the GenericDataStructureRequestType for querying purposes. The observation dimension is fixed to TIME_PERIOD. + + + + + + + + + + + + + + + + + + GenericDataStructureType defines the structural information for a generic data set. A reference to the structure, either explicitly or through a dataflow or provision agreement is required as well as the dimension which occurs at the observation level. + + + + + + + + + + + + + + + + + + + + + GenericTimeSeriesDataStructureType defines the structural information for a generic time series based data set. The dimension at the observation level is fixed to be TIME_PERIOD. + + + + + + + + + + + + + + + + + + StructureSpecificDataStructureType defines the structural information for a structured data set. In addition to referencing the data structure or dataflow which defines the structure of the data, the namespace for the data structure specific schema as well as which dimension is used at the observation level must be provided. It is also necessary to state whether the format uses explicit measures, although this is technically only applicable is the dimension at the observation level is the measure dimension or the flat data format is used. + + + + + + + + + + + + + + + + + + + + StructureSpecificDataTimeSeriesStructureType defines the structural information for a structure definition specific time series data set. The dimension at the observation level is fixed to be TIME_PERIOD. + + + + + + + + + + + + + + + + + + + + MetadataStructureType is an abstract base type the forms the basis of the structural information for any metadata message. A reference to the metadata structure definition or a metadataflow must be provided. This can be used to determine the structure of the message. + + + + + + + + ProvisionAgreement references a provision agreement which the metadata is reported against. + + + + + StructureUsage references a metadataflow which the metadata is reported against. + + + + + Structure references the metadata structure definition which defines the structure of the metadata. + + + + + + + + + + + + + StructureSpecificMetadataStructureType defines the structural information for a structured metadata message. + + + + + + + + + + + + + + + + + + + GenericMetadataStructureType defines the structural information for a generic metadata message. + + + + + + + + + + + + + + + + + + ObservationDimensionType allows for the dimension at the observation level to be specified by either providing the dimension identifier or using the explicit value "AllDimensions". + + + + + + + ObsDimensionsCodeType is an enumeration containing the values "TimeDimension" and "AllDimensions" + + + + + AllDimensions notes that the cross sectional format shall be flat; that is all dimensions should be contained at the observation level. + + + + + TIME_PERIOD refers to the fixed identifier for the time dimension. + + + + + + + + DataTypeType provides an enumerated list of the types of data formats allowed as the for the representation of an object. + + + + + A string datatype corresponding to W3C XML Schema's xs:string datatype. + + + + + A string datatype which only allows for the simple aplhabetic charcter set of A-Z, a-z. + + + + + A string datatype which only allows for the simple alphabetic character set of A-Z, a-z plus the simple numeric character set of 0-9. + + + + + A string datatype which only allows for the simple numeric character set of 0-9. This format is not treated as an integer, and therefore can having leading zeros. + + + + + An integer datatype corresponding to W3C XML Schema's xs:integer datatype. + + + + + An integer datatype corresponding to W3C XML Schema's xs:int datatype. + + + + + A numeric datatype corresponding to W3C XML Schema's xs:long datatype. + + + + + A numeric datatype corresponding to W3C XML Schema's xs:short datatype. + + + + + A numeric datatype corresponding to W3C XML Schema's xs:decimal datatype. + + + + + A numeric datatype corresponding to W3C XML Schema's xs:float datatype. + + + + + A numeric datatype corresponding to W3C XML Schema's xs:double datatype. + + + + + A datatype corresponding to W3C XML Schema's xs:boolean datatype. + + + + + A datatype corresponding to W3C XML Schema's xs:anyURI datatype. + + + + + A simple incrementing Integer type. The isSequence facet must be set to true, and the interval facet must be set to "1". + + + + + This value indicates that the startValue and endValue attributes provide the inclusive boundaries of a numeric range of type xs:decimal. + + + + + This value indicates that the startValue and endValue attributes provide the exclusive boundaries of a numeric range, of type xs:decimal. + + + + + This value indicates that the value increments according to the value provided in the interval facet, and has a true value for the isSequence facet. + + + + + Observational time periods are the superset of all time periods in SDMX. It is the union of the standard time periods (i.e. Gregorian time periods, the reporting time periods, and date time) and a time range. + + + + + Standard time periods is a superset of distinct time period in SDMX. It is the union of the basic time periods (i.e. the Gregorian time periods and date time) and the reporting time periods. + + + + + BasicTimePeriod time periods is a superset of the Gregorian time periods and a date time. + + + + + Gregorian time periods correspond to calendar periods and are represented in ISO-8601 formats. This is the union of the year, year month, and date formats. + + + + + A Gregorian time period corresponding to W3C XML Schema's xs:gYear datatype, which is based on ISO-8601. + + + + + A time datatype corresponding to W3C XML Schema's xs:gYearMonth datatype, which is based on ISO-8601. + + + + + A time datatype corresponding to W3C XML Schema's xs:date datatype, which is based on ISO-8601. + + + + + Reporting time periods represent periods of a standard length within a reporting year, where to start of the year (defined as a month and day) must be defined elsewhere or it is assumed to be January 1. This is the union of the reporting year, semester, trimester, quarter, month, week, and day. + + + + + A reporting year represents a period of 1 year (P1Y) from the start date of the reporting year. This is expressed as using the SDMX specific ReportingYearType. + + + + + A reporting semester represents a period of 6 months (P6M) from the start date of the reporting year. This is expressed as using the SDMX specific ReportingSemesterType. + + + + + A reporting trimester represents a period of 4 months (P4M) from the start date of the reporting year. This is expressed as using the SDMX specific ReportingTrimesterType. + + + + + A reporting quarter represents a period of 3 months (P3M) from the start date of the reporting year. This is expressed as using the SDMX specific ReportingQuarterType. + + + + + A reporting month represents a period of 1 month (P1M) from the start date of the reporting year. This is expressed as using the SDMX specific ReportingMonthType. + + + + + A reporting week represents a period of 7 days (P7D) from the start date of the reporting year. This is expressed as using the SDMX specific ReportingWeekType. + + + + + A reporting day represents a period of 1 day (P1D) from the start date of the reporting year. This is expressed as using the SDMX specific ReportingDayType. + + + + + A time datatype corresponding to W3C XML Schema's xs:dateTime datatype. + + + + + TimeRange defines a time period by providing a distinct start (date or date time) and a duration. + + + + + A time datatype corresponding to W3C XML Schema's xs:gMonth datatype. + + + + + A time datatype corresponding to W3C XML Schema's xs:gMonthDay datatype. + + + + + A time datatype corresponding to W3C XML Schema's xs:gDay datatype. + + + + + A time datatype corresponding to W3C XML Schema's xs:time datatype. + + + + + A time datatype corresponding to W3C XML Schema's xs:duration datatype. + + + + + This value indicates that the content of the component can contain XHTML markup. + + + + + This value indicates that the content of the component will be data key (a set of dimension references and values for the dimensions). + + + + + This value indicates that the content of the component will be complete reference (either URN or full set of reference fields) to an Identifiable object in the SDMX Information Model. + + + + + This value indicates that the content of the component will be reference to a data provider, which is actually a formal reference to a data provider and a data set identifier value. + + + + + This value indicates that the content of the component will be reference to an attachment constraint, which is actually a combination of a collection of full or partial key values and a reference to a data set or data structure, usage, or provision agreement. + + + + + + + + BasicComponentDataType provides an enumerated list of the types of characters allowed in the textType attribute for all non-target object components. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SimpleDataType restricts BasicComponentDataType to specify the allowable data types for a data structure definition component. The XHTML representation is removed as a possible type. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TimeDataType restricts SimpleDataType to specify the allowable data types for representing a time value. + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXCommonReferences.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXCommonReferences.xsd new file mode 100644 index 0000000..545af88 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXCommonReferences.xsd @@ -0,0 +1,4951 @@ + + + + + + + SDMX Common References Module + The common references module contains common constructs that are used to reference objects. + + + + + + + NestedIDType is the least restrictive form of an identifier used throughout all SDMX-ML messages. It allows for a hierarchical identifier, with each portion separated by the '.' character. For the identifier portions, valid characters include A-Z, a-z, @, 0-9, _, -, $. + + + + + + + + + TwoLevelIDType defines an identifier with exactly two levels. + + + + + + + + + IDType provides a type which is used for restricting the characters in codes and IDs throughout all SDMX-ML messages. Valid characters include A-Z, a-z, @, 0-9, _, -, $. + + + + + + + + + NCNameIDType restricts the IDType, so that the id may be used to generate valid XML components. IDs created from this type conform to the W3C XML Schema NCNAME type, and therefore can be used as element or attribute names. + + + + + + + + + NestedNCNameIDType restricts the NestedIDType, so that the id may be used to generate valid XML components. IDs created from this type conform to the W3C XML Schema NCNAME type, and therefore can be used as element or attribute names. + + + + + + + + + SingleNCNameIDType restricts the NestedNCNameIDType to allow only one level. Note that this is the same pattern as the NCNameIDType, but can be used when the base type to be restricted is a nested NCNameIDType (where as the NCNameIDType could only restrict the IDType). + + + + + + + + + VersionType is used to communicate version information. The format is restricted to allow for simple incrementing and sorting of version number. The version consists of an unlimited set of numeric components, separated by the '.' character. When processing version, each numeric component (the number preceding and following any '.' character) should be parsed as an integer. Thus, a version of 1.3 and 1.03 would be equivalent, as both the '3' component and the '03' component would parse to an integer value of 3. + + + + + + + + + VersionQueryType combines the VersionType and LateBoundVersionType to allow one to query for either a specific version of an object, or the latest version by specifying the '*' value. + + + + + + + LateBoundVersionType is a single value code list, used to include the '*' character - indicating that the latest version of an object is required. + + + + + Indicates that the latest version of an object is requested. + + + + + + + + EmptyType is an empty complex type for elements where the presence of the tag indicates all that is necessary. + + + + + + + + ReferenceType is an abstract base type. It is used as the basis for all references, to all for a top level generic object reference that can be substituted with an explicit reference to any object. Any reference can consist of a Ref (which contains all required reference fields separately) and/or a URN. These must result in the identification of the same object. Note that the Ref and URN elements are local and unqualified in order to allow for refinement of this structure outside of the namespace. This allows any reference to further refined by a different namespace. For example, a metadata structure definition specific metadata set might wish to restrict the URN to only allow for a value from an enumerated list. The general URN structure, for the purpose of mapping the reference fields is as follows: urn:sdmx:org.package-name.class-name=agency-id:(maintainable-parent-object-id[maintainable-parent-object-version].)?(container-object-id.)?object-id([object-version])?. + + + + + + Ref is used to provide a complete set of reference fields. Derived reference types will restrict the RefType so that the content of the Ref element requires exactly what is needed for a complete reference. + + + + + URN is used to hold the URN of the referenced object. This must be the same URN that would be constructed from the individual fields in the Ref element. + + + + + + URN is used to hold the URN of the referenced object. + + + + + + + + RefBaseType is an abstract base type the defines the basis for any set of complete reference fields. This should be refined by derived types so that only the necessary fields are available and required as necessary. This can be used for both full and local references (when some of the values are implied from another context). A local reference is indicated with the local attribute. The values in this type correspond directly to the components of the URN structure, and thus can be used to compose a URN when the local attribute value is false. As this is the case, any reference components which are not part of the URN structure should not be present in the derived types. + + + + The agencyID attribute identifies the maintenance agency for the object being referenced (agency-id in the URN structure). This is optional to allow for local references (where the other reference fields are inferred from another context), but all complete references will require this. + + + + + The maintainableParentID attribute identifies the maintainable object in which the referenced object is defined, if applicable (maintainable-parent-object-id in the URN structure). This is only used in references where the referenced object is not itself maintainable. + + + + + The maintainableParentVersion attribute identifies the version of the maintainable object in which the referenced object is defined (maintainable-parent-object-version in the URN structure). This is only used in references where the referenced object is not itself maintainable. This should only be used when the maintainableParentID is present. If this is available, a default of 1.0 will always apply. + + + + + The containerID attribute identifies the object within a maintainable object in which the referenced object is defined (container-object-id in the URN structure). This is only used in references where the referenced object is not contained directly within a maintainable object (e.g. a Component within a ComponentList, within a maintainable Structure). If the container has a fixed identifier, this attribute will not be present. + + + + + The id attribute identifies the object being referenced, and is therefore always required. + + + + + The version attribute identifies the version of the object being reference, if applicable. If this is available, a default value of 1.0 will always apply. + + + + + The local attribute indicates whether this set of reference fields is meant for local referencing, in which case some of the reference fields will be implied from another context. Concrete instances of this class will always fix this value to either true or false, depending on their intended usage. If the value is fixed to true, then the complete set of reference fields will be required and a URN can be fully composed from the values. + + + + + The class attribute indicates the class name of the object being referenced. This attribute allows any reference to be processed generically from this definition. References derived from this should fix the value of this attribute to indicate the type of object that is being referenced, or in the case that a reference which allows specific types of fields, the representation should be sub-setted to the appropriate values. + + + + + The package attribute indicates the package name for the object being referenced. This attribute allows any reference to be processed generically from this definition. References derived from this should fix the value of this attribute to indicate the type of object that is being referenced, or in the case that a reference which allows specific types of fields, the representation should be sub-setted to the appropriate values. + + + + + + + ObjectReferenceType is a generic reference which allows for any object to be referenced. The type of object actually referenced can be determined from the URN or from the class attribute of the full set of reference fields. + + + + + + + + + + + + + + + + + ObjectRefType contains a set of reference fields for the purpose of referencing any object. This cannot be a local reference, therefore the agency identifier is required. It is also required that the class and package be supplied for the referenced object such that a complete URN reference can be built from the values provided. Note that this is not capable of fully validating that all necessary fields are supplied for a given object type. + + + + + + + + + + + + + + MaintainableRefBaseType is an abstract base type for referencing a maintainable object. + + + + + + + + + + + + + + + + + + + MaintainableRefType contains a complete set of reference fields for referencing any maintainable object. + + + + + + + + + + + + ItemSchemeRefBaseType is an abstract base type for referencing an item scheme. + + + + + + + + + + + + + + + + ItemSchemeRefType contains a complete set of reference fields for referencing any item scheme. The class and package a required so that the reference is explicit as to the exact object being referenced. + + + + + + + + + + + + StructureOrUsageRefBaseType is an abstract base type for referencing a structure or structure usage. + + + + + + + + + + + + + + + + StructureRefBaseType is an abstract base type for referencing a structure. + + + + + + + + + + + + + + + + StructureRefType contains a set of reference fields for referencing any structure. + + + + + + + + + + + + StructureUsageRefBaseType is an abstract base type for referencing a structure usage. + + + + + + + + + + + + + + + + StructureUsageRefType contains a set of reference fields for referencing any structure usage. + + + + + + + + + + + + ChildObjectRefBaseType is an abstract base type for referencing any child object defined directly within a maintainable object. + + + + + + + + + + + + + + + + + + + ContainerChildObjectRefBaseType is an abstract base type for referencing any child object within container defined in a maintainable object. + + + + + + + + + + + + + + + + + + ItemRefBaseType is an abstract base type for referencing an item within an item scheme. + + + + + + + The maintainableParentID references the item scheme in which the item being referenced is defined. + + + + + The maintainableParentVersion attribute references the version of the item scheme in which the item being referenced is defined. If not supplied, a default value of 1.0 is assumed. + + + + + + + + + + + + + ComponentListRefBaseType is an abstract base type for referencing a component list within a structure. + + + + + + + The maintainableParentID references the structure in which the component list being referenced is defined. + + + + + The maintainableParentVersion attribute references the version of the structure in which the component list being referenced is defined. If not supplied, a default value of 1.0 is assumed. + + + + + + + + + + + + + ComponentRefBaseType is an abstract base type for referencing a component contained in a component list within a structure. + + + + + + + The maintainableParentID references the structure in which the component being referenced is defined. + + + + + The maintainableParentVersion attribute references the version of the structure in which the component being referenced is defined. If not supplied, a default value of 1.0 is assumed. + + + + + The containerID attribute references the component list of that contains the component being referenced. It is optional for the cases where the component list has a fixed identifier. Specific implementations of this will prohibit or require this accordingly. + + + + + + + + + + + + + AnyCodelistRefType is a type for referencing any codelist object (either a codelist or a hierarchical codelist). + + + + + + + + + + + + StructureOrUsageRefType is a type for referencing a structure or structure usage. + + + + + + + + + + + + LocalIdentifiableRefBaseType is an abstract base type which provides a local reference to any identifiable object. + + + + + + + + + + + + + + + + + + + LocalItemRefBaseType is an abstract base type which provides a local reference to a item object. + + + + + + + + + + + + + + LocalComponentListRefBaseType is an abstract base type which provides a local reference to a component list object. + + + + + + + + + + + + + LocalComponentRefBaseType is an abstract base type which provides a local reference to a component object. + + + + + + + + + + + LocalComponentListComponentRefType provides a local reference to any component object within a specific component list. References for both of these are required as well as an indication of which type of type of component is being referenced via the class attribute. + + + + + + + + + + + + + + + LocalComponentRefBaseType is an abstract base type which provides a local reference to a component object. + + + + + + + + + + + LocalComponentRefType provides a local reference to any type component object. + + + + + + + + + + + + AnyLocalCodeRefType provides a local reference to any code object. + + + + + + + + + The containerID attribute references the hierarchy which defines the hierarchical code in the case that this reference is for a hierarchical code. + + + + + + + + + + + + + + + URNReferenceType is a type referencing any object via its URN. The exact type of object is not specified, although it can be determined from the URN value. + + + + + + + + + + + + + MaintainableReferenceBaseType is an abstract base type for referencing a maintainable object. It consists of a URN and/or a complete set of reference fields; agency, id, and version. + + + + + + + + + + + + + + + + + MaintainableReferenceType is a type for referencing any maintainable object. It consists of a URN and/or a complete set of reference fields; agency, id, and version. + + + + + + + + + + + + + + + + + LocalIdentifiableReferenceType is an abstract base type for referencing an identifiable object locally, where the maintainable object in which it is defined is referenced in another context.. + + + + + + + + + + + + + StructureReferneceBaseType is a specific type of MaintainableReference that is used for referencing structure definitions. It consists of a URN and/or a complete set of reference fields; agency, id, and version. + + + + + + + + + + + + + + + + + StructureReferenceType is a specific type of MaintainableReference that is used for referencing any structure. It consists of a URN and/or a complete set of reference fields; agency, id, and version. + + + + + + + + + + + + + + + + + StructureUsageReferenceBaseType is a specific type of MaintainableReference that is used for referencing structure usages. It consists of a URN and/or a complete set of reference fields; agency, id, and version. + + + + + + + + + + + + + + + + + StructureUsageReferenceType is a specific type of MaintainableReference that is used for referencing any structure usages. It consists of a URN and/or a complete set of reference fields; agency, id, and version. + + + + + + + + + + + + + + + + + ItemSchemeReferenceBaseType is a specific type of MaintainableReference that is used for referencing item schemes. It consists of a URN and/or a complete set of reference fields; agency, id, and version. + + + + + + + + + + + + + + + + + ItemSchemeReferenceType is a reference that is used for referencing any type of item scheme. It consists of a URN and/or a complete set of reference fields; agency, id, and version. + + + + + + + + + + + + + + + + + ChildObjectReferenceType is an abstract base type used for referencing a particular object defined directly within a maintainable object. It consists of a URN and/or a complete set of reference fields; agency, maintainable id (maintainableParentID), maintainable version (maintainableParentVersion), the object id (which can be nested), and optionally the object version (if applicable). + + + + + + + + + + + + + + + + + ContainerChildObjectReferenceType is an abstract base type used for referencing a particular object defined in a container object within a maintainable object. It consists of a URN and/or a complete set of reference fields; agency, maintainable id (maintainableParentID), maintainable version (maintainableParentVersion), container id (which is optional in order to allow for containers with fixed values to be omitted), container version (if applicable), the object id (which can be nested), and optionally the object version (if applicable). + + + + + + + + + + + + + + + + + ItemReferenceType is an abstract base type used for referencing a particular item within an item scheme. Note that this reference also has the ability to reference items contained within other items inside of the item scheme. It consists of a URN and/or a complete set of reference fields; agency, scheme id (maintainableParentID), scheme version (maintainableParentVersion), and item id (which can be nested). + + + + + + + + + + + + + + + + + ComponentListReferenceType is an abstract base type used for referencing component lists within a structure. It consists of a URN and/or a complete set of reference fields (structure agency, structure id, structure version, and component list id). + + + + + + + + + + + + + + + + + ComponentReferenceType is an abstract base type used for referencing components within a structure definition. It consists of a URN and/or a complete set of reference fields (structure agency, structure id, structure version, component list id, and component id). + + + + + + + + + + + + + + + + + LocalItemReferenceType is an abstract base type which provides a simple reference to an item where the reference to the item scheme which defines it are provided in another context. + + + + + + + + + + + + + LocalComponentListReferenceType is an abstract base type which provides a simple reference to a component list where the reference to the structure which defines it is provided in another context. + + + + + + + + + + + + + LocalComponentListComponentReferenceBaseType is an abstract base type which provides a simple reference to any type of component in a specific component list where the reference to the structure which defines it are provided in another context, and the component list may or may not be defined in another context. + + + + + + + + + + + + + LocalComponentListComponentReferenceType provides a simple reference to any type of component in a specific component list where the reference to the structure which defines it are provided in another context. + + + + + + + + + + + + + LocalComponentReferenceBaseType is an abstract base type which provides a simple reference to a component where the references to the component list which contains it and the structure which defines it are provided in another context. + + + + + + + + + + + + + LocalComponentReferenceType provides a simple reference to any type of component in a component list where the references to the component list and the structure which defines them are provided in another context. + + + + + + + + + + + + + StructureOrUsageReferenceType is a specific type of a reference for referencing either a structure or a structure usage. It consists of a URN and/or a complete set of reference fields; agency, id and version. If the complete set of reference fields is used, it is required that a class and package be provided so that the type of object referenced is clear. + + + + + + + + + + + + + + + + + + + CategorisationReferenceType is a type for referencing a categorisation object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + CategorisationRefType provides a reference to a categorisation via a complete set of reference fields. + + + + + + + + + + + + CategorySchemeReferenceType is a type for referencing a category scheme object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + CategorySchemeRefType provides a reference to a category scheme via a complete set of reference fields. + + + + + + + + + + + + CategoryReferenceType is a type for referencing a category object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + CategoryRefType references a category from within a category scheme. Reference fields are required for both the scheme and the item. + + + + + + The maintainableParentID references the category scheme in which the category being referenced is defined. + + + + + The maintainableParentVersion attribute references the version of the category scheme in which the category being referenced is defined. If not supplied, a default value of 1.0 is assumed. + + + + + + + + + + + LocalCategoryReferenceType provides a simple references to a category where the identification of the category scheme which defines it is contained in another context. + + + + + + + + + + + + + LocalCategoryRefType references a category locally where the references to the category scheme which defines it is provided elsewhere. + + + + + + + + + + + + CodelistReferenceType is a type for referencing a codelist object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + CodelistRefType provides a reference to a codelist via a complete set of reference fields. + + + + + + + + + + + + CodeReferenceType is a type for referencing a code object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + CodeRefType references a code from within a codelist. Reference fields are required for both the scheme and the item. + + + + + + The maintainableParentID references the codelist in which the code being referenced is defined. + + + + + The maintainableParentVersion attribute references the version of the codelist in which the code being referenced is defined. If not supplied, a default value of 1.0 is assumed. + + + + + + + + + + + + LocalCodeReferenceType provides a simple references to a code where the identification of the codelist which defines it is contained in another context. + + + + + + + + + + + + + LocalCodeRefType references a code locally where the references to the codelist which defines it is provided elsewhere. + + + + + + + + + + + + + AnyCodelistReferenceType is a specific type of a reference for referencing either a codelist or a hierarchical codelist usage. It consists of a URN and/or a complete set of reference fields; agency, id and version. If the complete set of reference fields is used, it is required that a class be provided so that the type of object referenced is clear. + + + + + + + + + + + + + + + + + AnyLocalCodeReferenceType provides a simple references to any code or hierarchical code where the identification of the codelist or hierarchical codelist which defines it is contained in another context. + + + + + + + + + + + + + + + + + ConceptSchemeReferenceType is a type for referencing a concept scheme object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + ConceptSchemeRefType provides a reference to a concept scheme via a complete set of reference fields. + + + + + + + + + + + + ConceptReferenceType is a type for referencing a concept object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + ConceptRefType references a concept from within a concept scheme. Reference fields are required for both the scheme and the item. + + + + + + The maintainableParentID references the concept scheme in which the concept being referenced is defined. + + + + + The maintainableParentVersion attribute references the version of the concept scheme in which the concept being referenced is defined. If not supplied, a default value of 1.0 is assumed. + + + + + + + + + + + + LocalConceptReferenceType provides a simple references to a concept where the identification of the concept scheme which defines it is contained in another context. + + + + + + + + + + + + + LocalConceptRefType references a concept locally where the references to the concept scheme which defines it is provided elsewhere. + + + + + + + + + + + + + OrganisationSchemeReferenceBaseType is a type for referencing a organisation scheme object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + OrganisationSchemeRefBaseType contains a set of reference fields for an organisation scheme. + + + + + + + + + + + + OrganisationSchemeReferenceType references an organisation scheme regardless of the specific type. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + OrganisationSchemeRefType provides a reference to an organisation scheme via a complete set of reference fields. It is required that the class (i.e. the type) of organisation scheme being referenced be specified. + + + + + + + + + + + OrganisationReferenceBaseType is a type for referencing any organisation object, regardless of its type. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + OrganisationRefBaseType is an abstract base type which references an organisation from within a organisation scheme. Reference fields are required for both the scheme and the organisation. + + + + + + The maintainableParentID references the organisation scheme in which the organisation being referenced is defined. + + + + + The maintainableParentVersion attribute references the version of the organisation scheme in which the organisation being referenced is defined. If not supplied, a default value of 1.0 is assumed. + + + + + + + + + + + + OrganisationReferenceType references an organisation regardless of the specific type. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + OrganisationRefType provides a reference to any organisation via a complete set of reference fields. It is required that the class (i.e. the type) of organisation being referenced be specified. + + + + + + + + + + + LocalOrganisationReferenceBaseType is an abstract base type which provides a simple references to an organisation, regardless of type, where the identification of the organisation scheme which defines it is contained in another context. + + + + + + + + + + + + + LocalOrganisationRefBaseType is an abstract base type that references an organisation locally where the reference to the organisation scheme which defines it is provided elsewhere. + + + + + + + + + + + + + LocalOrganisationReferenceType provides a simple reference to an organisation, regardless of type, where the identification of the organisation scheme which defines it is contained in another context. + + + + + + + + + + + + + LocalOrganisationRefType references an organisation locally where the reference to the organisation scheme which defines it is provided elsewhere. The reference requires that the class (i.e. the type) or the organisation being reference be provided. + + + + + + + + + + + + OrganisationUnitSchemeReferenceType is a type for referencing an organisation unit scheme object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + OrganisationUnitSchemeRefType contains a set of reference fields for an organisation unit scheme. + + + + + + + + + + + OrganisationUnitReferenceType is a type for referencing an organisation unit. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + OrganisationUnitRefType contains a set of reference fields for referencing an organisation unit within an organisation unit scheme. + + + + + + + + + + + LocalOrganisationUnitReferenceType provides a simple reference to an organisation unit, where the reference to the organisation unit scheme which defines it is provided in another context. + + + + + + + + + + + + + LocalOrganisationUnitRefType references an organisation unit locally where the reference to the organisation unit scheme which defines it is provided elsewhere. + + + + + + + + + + + AgencySchemeReferenceType is a type for referencing an agency scheme object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + AgencySchemeRefType contains a set of reference fields for an agency scheme. + + + + + + + + + + + AgencyReferenceType is a type for referencing an agency. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + AgencyRefType contains a set of reference fields for referencing an agency within an agency scheme. + + + + + + + + + + + LocalAgencyReferenceType provides a simple reference to an agency, where the reference to the agency scheme which defines it is provided in another context. + + + + + + + + + + + + + LocalAgencyRefType references an agency locally where the reference to the agency scheme which defines it is provided elsewhere. + + + + + + + + + + + DataConsumerSchemeReferenceType is a type for referencing a data consumer scheme object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + DataConsumerSchemeRefType contains a set of reference fields for a data consumer scheme. + + + + + + + + + + + DataConsumerReferenceType is a type for referencing a data consumer. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + DataConsumerRefType contains a set of reference fields for referencing a data consumer within a data consumer scheme. + + + + + + + + + + + LocalDataConsumerReferenceType provides a simple reference to a data consumer, where the reference to the data consumer scheme which defines it is provided in another context. + + + + + + + + + + + + + LocalDataConsumerRefType references a data consumer locally where the reference to the data consumer scheme which defines it is provided elsewhere. + + + + + + + + + + + DataProviderSchemeReferenceType is a type for referencing a data provider scheme object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + DataProviderSchemeRefType contains a set of reference fields for a data provider scheme. + + + + + + + + + + + DataProviderReferenceType is a type for referencing a data provider. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + DataProviderRefType contains a set of reference fields for referencing a data provider within a data provider scheme. + + + + + + + + + + + LocalDataProviderReferenceType provides a simple reference to a data provider, where the reference to the data provider scheme which defines it is provided in another context. + + + + + + + + + + + + + LocalDataProviderRefType references a data provider locally where the reference to the data provider scheme which defines it is provided elsewhere. + + + + + + + + + + + ReportingTaxonomyReferenceType is a type for referencing a reporting taxonomy object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + ReportingTaxonomyRefType provides a reference to a reporting taxonomy via a complete set of reference fields. + + + + + + + + + + + + ReportingCategoryReferenceType is a type for referencing a reporting category object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + ReportCategoryRefType contains a set of fields for referencing a reporting category within a reporting taxonomy. + + + + + + The maintainableParentID references the reporting taxonomy in which the reporting category being referenced is defined. + + + + + The maintainableParentVersion attribute references the version of the reporting taxonomy in which the reporting category being referenced is defined. If not supplied, a default value of 1.0 is assumed. + + + + + + + + + + + LocalReportingCategoryReferenceType provides a simple references to a reporting category where the identification of the reporting taxonomy which defines it is contained in another context. + + + + + + + + + + + + + LocalReportingCategoryRefType references a reporting category locally where the references to the reporting taxonomy which defines it is provided elsewhere. + + + + + + + + + + + + HierarchicalCodelistReferenceType is a type for referencing a hierarchical codelist object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + HierarchicalCodelistRefType contains a set of reference fields for a hierarchical codelist. + + + + + + + + + + + + HierarchyReferenceType is a type for referencing a hierarchy within a hierarchical codelist. + + + + + + + + + + + + + + + + + HierarchyRefType is type which references a hierarchy from within a hierarchical codelist. Reference fields are required for both the hierarchy and the codelist. + + + + + + + + + + + + + LevelReferenceType is a type for referencing a level object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + LevelRefType references a level from within a hierarchical codelist. Reference fields are required for both the level and the codelist. + + + + + + + + + + + + + LocalLevelReferenceType is a type for referencing a level object where the reference to the hierarchical codelist and the hierarchy in which it is defined is provided in another context (e.g. is inferred from the hierarchy in which the reference is defined). + + + + + + + + + + + + + LocalLevelRefType references a level object where the reference to the hierarchy in which it is contained and the hierarchical codelist which define it are provided in another context. + + + + + + + + + + + HierarchicalCodeReferenceType is a type for referencing a hierarchical code object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + HierarchicalCodeRefType references a code from within a hierarchical codelist. Reference fields are required for both the code and the codelist. + + + + + + The maintainableParentID references the hierarchical codelist in which the code being referenced is defined. + + + + + The maintainableParentVersion attribute references the version of the hierarchical codelist in which the code being referenced is defined. If not supplied, a default value of 1.0 is assumed. + + + + + The containerID references the hierarchy which contains the code being referenced is defined. + + + + + + + + + + + ConstraintReferenceType is a type for referencing a constraint object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + ConstraintRefType contains a set of reference fields for a constraint. + + + + + + + + + + + + AttachmentConstraintReferenceType is a type for referencing a attachment constraint object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + AttachmentConstraintRefType contains a set of reference fields for an attachment constraint. + + + + + + + + + + + ContentConstraintReferenceType is a type for referencing a content constraint object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + ContentConstraintRefType contains a set of reference fields for a content constraint. + + + + + + + + + + + DataflowReferenceType is a type for referencing a dataflow object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + DataflowRefType contains a set of reference fields for a data flow. + + + + + + + + + + + + MetadataflowReferenceType is a type for referencing a metadata flow object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + MetadataflowRefType contains a set of reference fields for a metadata flow. + + + + + + + + + + + + DataStructureReferenceType is a type for referencing a data structure definition object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + DataStructureRefType contains a set of reference fields for a data structure definition. + + + + + + + + + + + + KeyDescriptorReferenceType is a type for referencing a key descriptor object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + KeyDescriptorRefType contains a reference to the key descriptor within a data structure definition. + + + + + + + + + + + + + AttributeDescriptorReferenceType is a type for referencing an attribute descriptor object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + AttributeDescriptorRefType contains a reference to the attribute descriptor within a data structure definition. + + + + + + + + + + + + + MeasureDescriptorReferenceType is a type for referencing a measure descriptor object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + MeasureDescriptorRefType contains a reference to the measure descriptor within a data structure definition. + + + + + + + + + + + + + GroupKeyDescriptorReferenceType is a type for referencing a group key descriptor object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + GroupKeyDescriptorRefType contains a reference to a group key descriptor within a data structure definition. + + + + + + + + + + + + + LocalGroupKeyDescriptorReferenceType is a type for referencing a group key descriptor locally, where the reference to the data structure definition which defines it is provided in another context (for example the data structure definition in which the reference occurs). + + + + + + + + + + + + + LocalGroupKeyDescriptorRefType contains a local reference to a group key descriptor. + + + + + + + + + + + + DimensionReferenceType is a type for referencing a dimension object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + DimensionRefType contains a reference to a dimension within a data structure definition. Note that since there is only one key descriptor, the container reference fields are prohibited. + + + + + + + + + + + + + + MeasureDimensionReferenceType is a type for referencing a measure dimension object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + MeasureDimensionRefType contains a reference to the measure dimension within a data structure definition. Note that since there is only one key descriptor, the container reference fields are prohibited. + + + + + + + + + + + + + + TimeDimensionReferenceType is a type for referencing a time dimension object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + TimeDimensionRefType contains a reference to the time dimension within a data structure definition. Note that since there is only one key descriptor, the container reference fields are prohibited. + + + + + + + + + + + + + + LocalDimensionReferenceType is a type for referencing any type of dimension locally, where the reference to the data structure definition which defines the dimension is provided in another context (for example the data structure definition in which the reference occurs). + + + + + + + + + + + + + LocalDimensionRefType contains the reference fields for referencing a dimension locally. + + + + + + + The class attribute is optional and provided a default value of Dimension. It is strongly recommended that if the time or measure dimension is referenced, that the proper value be set for this field. However, this is not absolutely necessary since all data structure definition components must have a unique identifier within the scope of the entire data structure. It does, however, allow systems which will treat such a reference as a URN to easily construct the URN without having to verify the object class of the referenced dimension. + + + + + + + + + + AttributeReferenceType is a type for referencing an attribute object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + AttributeRefType contains a reference to an attribute within a data structure definition. Note that since there is only one attribute descriptor, the container reference fields are prohibited. + + + + + + + + + + + + + + PrimaryMeasureReferenceType is a type for referencing a primary measure object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + PrimaryMeasureRefType contains a reference to the primary measure within a data structure definition. Note that since there is only one key descriptor, the container reference fields are prohibited. + + + + + + + + + + + + + + LocalPrimaryMeasureReferenceType is a type for referencing a primary measure locally, where the reference to the data structure definition which defines the primary measure is provided in another context (for example the data structure definition in which the reference occurs). + + + + + + + + + + + + + LocalPrimaryMeasureRefType contains the reference fields for referencing a primary measure locally. + + + + + + + + + + + + + + LocalDataStructureComponentReferenceType is a type for referencing any type of data structure component locally, where the reference for the data structure definition which defines the components is available in another context. + + + + + + + + + + + + + LocalDataStructureComponentRefType contains the reference fields for referencing any data structure component locally. This reference must specify the class of the component being referenced. + + + + + + + + + + + + + + DataStructureEnumerationSchemeReferenceType is a type for referencing any type of item scheme that is allowable as the enumeration of the representation of a data structure definition component. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + DataStructureEnumerationSchemeRefType contains the reference fields for referencing any item scheme that is allowable as the enumeration of the representation of a data structure definition component. + + + + + + + + + + + + MetadataStructureReferenceType is a type for referencing a metadata structure definition object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + MetadataStructureRefType contains a set of reference fields for a metadata structure definition. + + + + + + + + + + + + MetadataTargetReferenceType is a type for referencing a metadata target object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + MetadataTargetRefType contains a reference to a metadata target within a metadata structure definition. + + + + + + + + + + + + + LocalMetadataTargetReferenceType is a type for referencing a metadata target locally, where the reference to the metadata structure definition which defines it is provided in another context (for example the metadata structure definition in which the reference occurs). + + + + + + + + + + + + + LocalMetadataTargetRefType contains a local reference to a metadata target object. + + + + + + + + + + + + ConstraintTargetReferenceType is a type for referencing a constraint target object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + ConstraintTargetRefType contains a reference to a constraint target within a metadata target of a data structure definition. + + + + + + + + + + + + + + DataSetTargetReferenceType is a type for referencing a data set target object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + DataSetTargetRefType contains a reference to a data set target within a metadata target of a data structure definition. + + + + + + + + + + + + + + KeyDescriptorValuesTargetType is a type for referencing a key descriptor values target object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + KeyDescriptorValuesTargetRefType contains a reference to a key descriptor values target within a metadata target of a data structure definition. + + + + + + + + + + + + + + ReportPeriodTargetReferenceType is a type for referencing a report period target object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + ReportPeriodTargetRefType contains a reference to a report period target within a metadata target of a data structure definition. + + + + + + + + + + + + + + IdentifiableObjectTargetReferenceType is a type for referencing an identifiable object target object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + IdentifiableObjectTargetRefType contains a reference to an identifiable object target within a metadata target of a data structure definition. + + + + + + + + + + + + + LocalTargetObjectReferenceType is a type for referencing any type of target object within a metadata target locally, where the references to the metadata target and the metadata structure definition which defines the target reference are provided in another context. + + + + + + + + + + + + + LocalTargetObjectRefType contains the reference fields for referencing a target object locally. + + + + + + + + + + + + ReportStructureReferenceType is a type for referencing a report structure object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + ReportStructureRefType contains a reference to a report structure within a metadata structure definition. + + + + + + + + + + + + + LocalReportStructureReferenceType is a type for referencing a report structure locally, where the reference to the metadata structure definition which defines it is provided in another context (for example the metadata structure definition in which the reference occurs). + + + + + + + + + + + + + LocalReportStructureRefType contains a local reference to a report structure object. + + + + + + + + + + + + MetadataAttributeReferenceType is a type for referencing a metadata attribute object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + MetadataAttributeRefType contains a reference to a metadata attribute within a report structure in a metadata structure definition. + + + + + + + + + + + + + + LocalMetadataStructureComponentReferenceType is a type for referencing any type of metadata structure component locally, where the reference for the metadata structure definition which defines the components is available in another context. + + + + + + + + + + + + + LocalMetadataStructureComponentRefType contains the reference fields for referencing any metadata structure component locally. This reference must specify the class of the component being referenced. + + + + + + + + + + + + + ProvisionAgreementReferenceType is a type for referencing a provision agreement. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + ProvisionAgreementRefType contains a set of reference fields for a provision agreement. + + + + + + + + + + + + ProcessReferenceType is a type for referencing a process object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + ProcessRefType contains a set of reference fields for a process. + + + + + + + + + + + + ProcessStepReferenceType is a type for referencing a process step object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + ProcessStepRefType provides for a reference to a process step through its id. Support for referencing nested process steps is provided through a nested identifier. + + + + + + + + + + + + LocalProcessStepReferenceType is a type for referencing a process step locally, where the reference to the process which defines it is provided in another context (for example the metadata structure definition in which the reference occurs). + + + + + + + + + + + + + LocalProcessStepRefType contains a local reference to a process step object. + + + + + + + + + + + + TransiationReferenceType is a type for referencing a process step object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + TransitionRefType provides for a reference to a transition definition in process step through its id. + + + + + + + + + + + + + StructureSetReferenceType is a type for referencing a structure set object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + StructureSetRefType contains a set of reference fields for a structure set. + + + + + + + + + + + + StructureMapReferenceType is a type for referencing a structure map object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + StructureMapRefType contains fields for referencing a structure map within a structure set. + + + + + + + + + + + + + CategorySchemeMapReferenceType is a type for referencing a category scheme map object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + CategorySchemeMapRefType contains a set of reference fields for a category scheme map. + + + + + + + + + + + + + CodelistMapReferenceType is a type for referencing a codelist map object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + CodelistMapRefType contains a set of reference fields for a codelist map. + + + + + + + + + + + + + LocalCodelistMapReferenceType is a type for referencing a codelist map object where the reference to the structure set which defines it is provided in another context (e.g. the structure set in which this reference occurs). + + + + + + + + + + + + + LocalCodelistMapRefType contains a set of reference fields for a codelist map locally. + + + + + + + + + + + + + ConceptSchemeMapReferenceType is a type for referencing a concept scheme map object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + ConceptSchemeMapRefType contains a set of reference fields for a concept scheme map. + + + + + + + + + + + + + OrganisationSchemeMapReferenceType is a type for referencing a organisation scheme map object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + OrganisationSchemeMapRefType contains a set of reference fields for an organisation scheme map. + + + + + + + + + + + + + VtlMappingSchemeReferenceType is a type for referencing a VTL mapping scheme object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + VtlMappingSchemeRefType provides a reference to a VTL mapping scheme via a complete set of reference fields. + + + + + + + + + + + + VtlMappingReferenceType is a type for referencing a VTL mapping object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + VtlMappingRefType references a VTL mapping from within a VTL mapping scheme. Reference fields are required for both the scheme and the item. + + + + + + The maintainableParentID references the VTL mapping scheme in which the VTL mapping being referenced is defined. + + + + + The maintainableParentVersion attribute references the version of the VTL mapping scheme in which the VTL mapping being referenced is defined. If not supplied, a default value of 1.0 is assumed. + + + + + + + + + + + + LocalVtlMappingReferenceType provides a simple reference to a VTL mapping where the identification of the VTL mapping scheme which defines it is contained in another context. + + + + + + + + + + + + + LocalVtlMappingRefType references a VTL mapping locally where the references to the VTL mapping scheme which defines it is provided elsewhere. + + + + + + + + + + + + + NamePersonalisationSchemeReferenceType is a type for referencing a name personalisation scheme object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + NamePersonalisationSchemeRefType provides a reference to a name personalisation scheme via a complete set of reference fields. + + + + + + + + + + + + NamePersonalisationReferenceType is a type for referencing a name personalisation object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + NamePersonalisationRefType references a name personalisation from within a name personalisation scheme. Reference fields are required for both the scheme and the item. + + + + + + The maintainableParentID references the name personalisation scheme in which the name personalisation being referenced is defined. + + + + + The maintainableParentVersion attribute references the version of the name personalisation scheme in which the name personalisation being referenced is defined. If not supplied, a default value of 1.0 is assumed. + + + + + + + + + + + + LocalNamePersonalisationReferenceType provides a simple reference to a name personalisation where the identification of the name personalisation scheme which defines it is contained in another context. + + + + + + + + + + + + + LocalNamePersonalisationRefType references a name personalisation locally where the references to the name personalisation scheme which defines it is provided elsewhere. + + + + + + + + + + + + + RulesetSchemeReferenceType is a type for referencing a ruleset scheme object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + RulesetSchemeRefType provides a reference to a ruleset scheme via a complete set of reference fields. + + + + + + + + + + + + RulesetReferenceType is a type for referencing a ruleset object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + RulesetRefType references a rule set from within an rule set scheme. Reference fields are required for both the scheme and the item. + + + + + + The maintainableParentID references the ruleset scheme in which the concept being referenced is defined. + + + + + The maintainableParentVersion attribute references the version of the ruleset scheme in which the ruleset being referenced is defined. If not supplied, a default value of 1.0 is assumed. + + + + + + + + + + + + LocalRulesetReferenceType provides a simple reference to a ruleset where the identification of the ruleset scheme which defines it is contained in another context. + + + + + + + + + + + + + LocalRulesetRefType references a ruleset locally where the references to the ruleset scheme which defines it is provided elsewhere. + + + + + + + + + + + + + TransformationSchemeReferenceType is a type for referencing a transformation scheme object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + TransformationSchemeRefType provides a reference to a transformation scheme via a complete set of reference fields. + + + + + + + + + + + + TransformationReferenceType is a type for referencing a transformation object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + TransformationRefType references a transformation from within a transformation scheme. Reference fields are required for both the scheme and the item. + + + + + + The maintainableParentID references the transformation scheme in which the transformation being referenced is defined. + + + + + The maintainableParentVersion attribute references the version of the transformation scheme in which the transformation being referenced is defined. If not supplied, a default value of 1.0 is assumed. + + + + + + + + + + + + LocalTransformationReferenceType provides a simple references to a transformation where the identification of the transformation scheme which defines it is contained in another context. + + + + + + + + + + + + + LocalTransformationRefType references a transformation locally where the references to the transformation scheme which defines it is provided elsewhere. + + + + + + + + + + + + + UserDefinedOperatorSchemeReferenceType is a type for referencing a user defined operator scheme object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + UserDefinedOperatorSchemeRefType provides a reference to a user defined operator scheme via a complete set of reference fields. + + + + + + + + + + + + UserDefinedOperatorReferenceType is a type for referencing a user defined operator object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + UserDefinedOperatorRefType references a user defined operator from within a user defined operator scheme. Reference fields are required for both the scheme and the item. + + + + + + The maintainableParentID references the user defined operator scheme in which the user defined operator being referenced is defined. + + + + + The maintainableParentVersion attribute references the version of the user defined operator scheme in which the user defined operator being referenced is defined. If not supplied, a default value of 1.0 is assumed. + + + + + + + + + + + + LocalUserDefinedOperatorReferenceType provides a simple reference to a user operator where the identification of the user defined operator scheme which defines it is contained in another context. + + + + + + + + + + + + + LocalUserDefinedOperatorRefType references a user defined operator locally where the references to the user defined operator scheme which defines it is provided elsewhere. + + + + + + + + + + + + + CustomTypeSchemeReferenceType is a type for referencing a custom type scheme object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + CustomTypeSchemeRefType provides a reference to a custom type scheme via a complete set of reference fields. + + + + + + + + + + + + CustomTypeReferenceType is a type for referencing a custom type object. It consists of a URN and/or a complete set of reference fields. + + + + + + + + + + + + + + + + + CustomTypeRefType references a custom type from within a user defined custom type scheme. Reference fields are required for both the scheme and the item. + + + + + + The maintainableParentID references the custom mask scheme in which the custom type being referenced is defined. + + + + + The maintainableParentVersion attribute references the version of the custom type scheme in which the custom type being referenced is defined. If not supplied, a default value of 1.0 is assumed. + + + + + + + + + + + + LocalCustomTypeReferenceType provides a simple reference to a custom type where the identification of the custom type scheme which defines it is contained in another context. + + + + + + + + + + + + + LocalCustomTypeRefType references a custom type locally where the references to the custom type scheme which defines it is provided elsewhere. + + + + + + + + + + + + + + + SetReferenceType defines the structure of a reference to a data/metadata set. A full reference to a data provider and the identifier for the data set must be provided. Note that this is not derived from the base reference structure since data/metadata sets are not technically identifiable. + + + + + DataProvider references a the provider of the data/metadata set. A URN and/or a complete set of reference fields must be provided. + + + + + ID contains the identifier of the data/metadata set being referenced. + + + + + + + + + + PackageTypeCodelistType provides an enumeration of all SDMX package names. + + + + + + + + + + + + + + + + + + ItemSchemePackageTypeCodelistType provides an enumeration of all SDMX packages which contain item schemes. + + + + + + + + + + + + + StructurePackageTypeCodelistType provides an enumeration of all SDMX packages which contain structure and structure usages. + + + + + + + + + + ObjectTypeCodelistType provides an enumeration of all objects outside of the base infomration model class. This includes some abstract object types such as Organsiation and Constraint. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MaintainableTypeCodelistType provides an enumeration of all maintainable objects. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ConcreteMaintainableTypeCodelistType provides an enumeration of all concrete maintainable objects. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CodelistTypeCodelistType provides an enumeration of all codelist objects. + + + + + + + + + + CodeTypeCodelistType provides an enumeration of all code objects. + + + + + + + + + + ConstraintTypeCodelistType provides an enumeration of all constraint objects. + + + + + + + + + + ItemSchemeTypeCodelistType provides an enumeration of all item scheme objects. + + + + + + + + + + + + + + + + + + + + + + DefinitionSchemeTypeCodelistType provides an enumeration of all definition scheme objects. + + + + + + + + + + + + + OrganisationSchemeTypeCodelistType provides an enumeration of all organisation scheme objects. + + + + + + + + + + + + OrganisationTypeCodelistType provides an enumeration of all organisation objects. + + + + + + + + + + + + StructureOrUsageTypeCodelistType provides an enumeration all structure and structure usage objects + + + + + + + + + + + + StructureTypeCodelistType provides an enumeration all structure objects + + + + + + + + + + StructureUsageTypeCodelistType provides an enumeration all structure usage objects + + + + + + + + + + ItemTypeCodelistType provides an enumeration of all item objects. + + + + + + + + + + + + + + + + + + + + + + ComponentListTypeCodelistType provides an enumeration of all component list objects. + + + + + + + + + + + + + + ComponentTypeCodelistType provides an enumeration of all component objects. + + + + + + + + + + + + + + + + + + + + DataStructureComponentTypeCodelistType provides an enumeration of all data structure component objects, except for the primary measure. + + + + + + + + + + + + + + DimensionEumerationSchemeTypeCodelistType provides an enumeration of all item schemes which are allowable as the representation of a data structure definition component. + + + + + + + + + + MetadataStructureComponentTypeCodelistType provides an enumeration of all metadata structure component objects. + + + + + + + + + + + + + + DimensionTypeCodelistType provides an enumeration of all dimension objects. + + + + + + + + + + + TargetObjectTypeCodelistType provides an enumeration of all target object objects. + + + + + + + + + + + + + Any is an empty element that denotes an object of any type. + + + + + + Agency is an empty element that denotes an agency object. + + + + + + AgencyScheme is an empty element that denotes an agency scheme object. + + + + + + AttachmentConstraint is an empty element that denotes an attachment constraint object. + + + + + + Attribute is an empty element that denotes an attribute object. + + + + + + AttributeDescriptor is an empty element that denotes an attribute descriptor object. + + + + + + Categorisation is an empty element that denotes a categorisation object. + + + + + + Category is an empty element that denotes a category object. + + + + + + CategorySchemeMap is an empty element that denotes a category scheme map object. + + + + + + CategoryScheme is an empty element that denotes a category scheme object. + + + + + + Code is an empty element that denotes a code object. + + + + + + CodeMap is an empty element that denotes a code map object. + + + + + + Codelist is an empty element that denotes a code list object. + + + + + + CodelistMap is an empty element that denotes a code list map object. + + + + + + ComponentMap is an empty element that denotes a component map object. + + + + + + Concept is an empty element that denotes a concept object. + + + + + + ConceptMap is an empty element that denotes a concept map object. + + + + + + ConceptScheme is an empty element that denotes a concept scheme object. + + + + + + ConceptSchemeMap is an empty element that denotes a concept scheme map object. + + + + + + ConstraintTarget is an empty element that denotes a constraint target object. + + + + + + ContentConstraint is an empty element that denotes a content constraint object. + + + + + + CustomType is an empty element that denotes a custom type object. + + + + + + CustomTypeScheme is an empty element that denotes a custom type scheme object. + + + + + + Dataflow is an empty element that denotes a data flow object. + + + + + + DataConsumer is an empty element that denotes a data consumer object. + + + + + + DataConsumerScheme is an empty element that denotes a data consumer scheme object. + + + + + + DataProvider is an empty element that denotes a data provider object. + + + + + + DataProviderScheme is an empty element that denotes a data provider scheme object. + + + + + + DataSetTarget is an empty element that denotes a data set target object. + + + + + + DataStructure is an empty element that denotes a data structure definition object. + + + + + + Dimension is an empty element that denotes a dimension object. + + + + + + DimensionDescriptor is an empty element that denotes a dimension descriptor object. + + + + + + DimensionDescriptorValuesTarget is an empty element that denotes a dimension descriptor values target object. + + + + + + GroupDimensionDescriptor is an empty element that denotes a group dimension descriptor object. + + + + + + HierarchicalCode is an empty element that denotes a hierarchical code object. + + + + + + HierarchicalCodelist is an empty element that denotes a hierarchical codelist object. + + + + + + Hierarchy is an empty element that denotes a hierarchy within a hiearcharchical codelist. + + + + + + HybridCodelistMap is an empty element that denotes a hybrid codelist map object. + + + + + + HybridCodeMap is an empty element that denotes a hybrid code map object. + + + + + + IdentifiableObjectTarget is an empty element that denotes an identifiable object target object. + + + + + + Level is an empty element that denotes a level object. + + + + + + MeasureDescriptor is an empty element that denotes a measure descriptor object. + + + + + + MeasureDimension is an empty element that denotes a measure dimension object. + + + + + + Metadataflow is an empty element that denotes a metadata flow object. + + + + + + MetadataAttribute is an empty element that denotes a metadata attribute object. + + + + + + MetadataSet is an empty element that denotes a metadata set object. + + + + + + MetadataStructure is an empty element that denotes a metadata structure definition object. + + + + + + MetadataTarget is an empty element that denotes a metadata target object. + + + + + + NamePersonalisation is an empty element that denotes a name personalisation object. + + + + + + NamePersonalisationScheme is an empty element that denotes a name personalisation scheme object. + + + + + + OrganisationMap is an empty element that denotes an organisation map object. + + + + + + OrganisationSchemeMap is an empty element that denotes an organisation scheme map object. + + + + + + OrganisationUnit is an empty element that denotes an organisation unit object. + + + + + + OrganisationUnitScheme is an empty element that denotes an organisation unit scheme object. + + + + + + PrimaryMeasure is an empty element that denotes a primary measure object. + + + + + + Process is an empty element that denotes a process object. + + + + + + ProcessStep is an empty element that denotes a process step object. + + + + + + ProvisionAgreement is an empty element that denotes a provision agreement object. + + + + + + ReportingCategory is an empty element that denotes a reporting category object. + + + + + + ReportingCategoryMap is an empty element that denotes a reporting category map object. + + + + + + ReportingTaxonomy is an empty element that denotes a reporting taxonomy object. + + + + + + ReportingTaxonomyMap is an empty element that denotes a reporting taxonomy map object. + + + + + + ReportPeriodTarget is an empty element that denotes a report period target object. + + + + + + ReportStructure is an empty element that denotes a report structure object. + + + + + + Ruleset is an empty element that denotes a ruleset object. + + + + + + RulesetScheme is an empty element that denotes a ruleset scheme object. + + + + + + StructureMap is an empty element that denotes a structure map object. + + + + + + StructureSet is an empty element that denotes a structure set object. + + + + + + TimeDimension is an empty element that denotes a time dimension object. + + + + + + Transformation is an empty element that denotes a transformation object. + + + + + + TransformationScheme is an empty element that denotes a transformation scheme object. + + + + + + Transition is an empty element that denotes a transition object. + + + + + + UserDefinedOperator is an empty element that denotes an user defined operator object. + + + + + + UserDefinedOperatorScheme is an empty element that denotes an user defined operator scheme object. + + + + + + VtlMapping is an empty element that denotes a VTL Mapping object. + + + + + + VtlMappingScheme is an empty element that denotes a VTL mapping scheme object. + + + + + + ObjectTypeListType provides a means for enumerating object types. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MaintainableObjectTypeListType provides a means for enumerating maintainable object types. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataGeneric.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataGeneric.xsd new file mode 100644 index 0000000..7d05cde --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataGeneric.xsd @@ -0,0 +1,12 @@ + + + + + + + + SDMX Generic Data Namespace Module + The generic data namespace module defines the generic (non-data structure definition specific) format for data. + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataGenericBase.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataGenericBase.xsd new file mode 100644 index 0000000..21ad0fc --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataGenericBase.xsd @@ -0,0 +1,216 @@ + + + + + + + SDMX Base Generic Data Module + The base generic data module contains the descriptions of base generic data set format. The data set defined here describes the structure of the data set in all generic data messages. Any generic data messages must derive the data set from this format. + + + + + DataSetType defines the structure of the generic data set. Data is organised into either a collection of series (grouped observations) or a collection of un-grouped observations. The organisation used is dependent on the structure specification in the header of the data message (which is referenced via the structureRef attribute). The structure specification states which data occurs at the observation level. If this dimension is "AllDimensions" then the data set must consist of a collection of un-grouped observations; otherwise the data set will contain a collection of series with the observations in the series disambiguated by the specified dimension at the observation level. This data set is capable of containing data (observed values) and/or documentation (attribute values). It is assumed that each series or un-grouped observation will be distinct in its purpose. For example, if series contains both data and documentation, it assumed that each series will have a unique key. If the series contains only data or only documentation, then it is possible that another series with the same key might exist, but with not with the same purpose (i.e. to provide data or documentation) as the first series. + + + + + + + DataProvider contains a reference to the provider for the data set. + + + + + Attributes contains the collection of attribute values for attributes defined in the data structure definition which do not have an attribute relationship with any other data structure definition components. + + + + + Group contains a references to a defined group in the data structure definition along with its key (if necessary) and values for the attributes which are associated with the group. An attribute is associated to a group by either an explicit group relationship or by a group attachment when the attribute has a relationship with a dimension which is a member of this group. + + + + + + Series contains a collection of observations that share a common key (set of dimension values). The key of a series is every dimension defined in the data structure definition, save the dimension which is declared in the structure specification to be at the observation level. In addition to the key and observations, the series contains values for attributes which have a relationship with any dimension that is part of the series key, so long as the attribute does not specify an attachment group or also has a relationship with the dimension declared to be at the observation level. + + + + + Obs is an un-grouped observation. This observation has a key which is a set of values for all dimensions declared in the data structure definition. In addition to the key, the value of the observation can be provided along with values for all attributes which have an association with the primary measure or any dimension (so long as it does not specify a group attachment). + + + + + + + + + + + + GroupType defines a structure which is used to communicate attribute values for a group defined in a data structure definition. The group can consist of either a subset of the dimensions defined by the data structure definition, or an association to an attachment constraint, which in turn defines key sets to which attributes can be attached. In the case that the group is based on an attachment constraint, only the identification of group is provided. It is expected that a system which is processing this will relate that identifier to the key sets defined in the constraint and apply the values provided for the attributes appropriately. + + + + + + + GroupKey contains the values for each dimension defined as being a member of the referenced group in the data structure definition. A value must be provided for every group dimension. This is optional, and not used if the group is defined as an association to an attachment constraint rather than a subset of the data structure definition dimensions. + + + + + Attributes contains the set of attribute values which are reported for group. The attribute values provided here apply to all data matching the partial key defined by the group key or the key sets of the associated attachment constraint. + + + + + + The type attribute holds the identifier assigned to the group in the data structure definition for which attribute values are being provided. + + + + + + + + + SeriesType defines a structure which is used to group a collection of observations which have a key in common. The key for a series is every dimension defined in the data structure definition, save the dimension declared to be at the observation level for this data set. In addition to observations, values can be provided for attributes which are associated with the dimensions which make up this series key (so long as the attributes do not specify a group attachment or also have an relationship with the observation dimension). It is possible for the series to contain only observations or only attribute values, or both. + + + + + + + SeriesKey contains the values for each all dimensions defined in the data structure definition, except for that which is declared to be at the observation level for this data set. This key is required, and every dimension must be provided a value. + + + + + Attributes contains the values for attributes which are associated with the dimensions which make up the series key, so long as the attributes do not also specify an attachment group or have a relationship with the observation dimension. + + + + + Obs contains an observation which shares the dimensionality of the series key. These observations are disambiguated from one another within this series by a single dimension value provided for each dimension. The dimension which provides this observation key is declared in the structure specification for the data set, which is provided in the header of the data message. + + + + + + + + + + ObsOnlyType defines the structure for an un-grouped observation. Unlike a group observation, an un-grouped must provided a full set of values for every dimension declared in the data structure definition. The observation can contain an observed value and/or a collection of attribute values. + + + + + + + ObsKey contains the values for every dimension defined in the data structure definition. A value must be provided for each dimension. This key serves to disambiguate the un-grouped observation within the data set. + + + + + ObsValue type contains the value for the observation. + + + + + Attributes contains the set of values reported for the attributes which have an association with the primary measure or any dimension in the data structure definition (so long as an attachment group is not also specified). + + + + + + + + + + ObsType defines the structure of a grouped observation. The observation must be provided a value for the dimension which is declared to be at the observation level for this data set. This dimension value should disambiguate the observation within the series in which it is defined (i.e. there should not be another observation with the same dimension value). The observation can contain an observed value and/or attribute values. + + + + + + + ObsDimension holds the key for the grouped observation, i.e. the value of the observation dimension. Note that in this element, the reference to the dimension is optional, since it can be inferred from the structure specification for the data set. This saves having to repeat the value unnecessarily. It is assumed that any application processing the data set will have the information from the structure specification available, so that if a dimension identifier is not supplied here, the proper reference can be applied. + + + + + ObsValue type contains the value for the observation. + + + + + Attributes contains the set of values reported for the attributes which have an association with the primary measure or the observations dimension (so long as an attachment group is not also specified). + + + + + + + + + + ValuesType is a general structure which contains a collection of data structure definition component values. This type is used to provide both key and attribute collection values. + + + + + Value contains a component value and a reference to the component for which a value is being provided. + + + + + + + + BaseValueType is a general structure which contains a reference to a data structure definition component and a value for that component. In this structure the reference to the component is optional to allow for usages where the actual reference might be provided in another context. + + + + The id attribute contains the identifier for the component for which a value is being provided. + + + + + The value attribute contains the provided component value. + + + + + + + ObsValueType is a derivation of the BaseValueType which is used to provide an observation value. Since an observation value is always associated with the data structure definition primary measure, and the identifier for the primary measure is fixed, the component reference for this structure is fixed. Note that this means that it is not necessary to provide a value in an instance as the fixed value will be provided in the post validation information set. + + + + + + The id attribute contains a fixed reference to the primary measure component of the data structure definition. + + + + + + + + + + ComponentValueType is a derivation of the BaseValueType which requires that the component reference be provided. This is used when the identification of the component cannot be inferred from another context. + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataGenericTimeSeries.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataGenericTimeSeries.xsd new file mode 100644 index 0000000..f40b6f9 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataGenericTimeSeries.xsd @@ -0,0 +1,87 @@ + + + + + + + + SDMX Time Series Generic Data Module + The time series generic data module contains the descriptions of a derivation of the base generic data set format which only allows for data organised as time series. A data set structured according to the data set defined here is a valid base generic data set, and can be processed using the same rules as those for the base format. The difference in this structure is that the data is assured to be organised as time series. This allows for variations of the generic data message which restrict the data to only be formatted as time series. + + + + + TimeSeriesDataSetType is a derivation of the base DataSetType of the generic format the restricts the data set to only allow for grouped observations where the dimension at the observation level is the time dimension of the data structure definition. This means that unlike the base data set structure, there can be no un-grouped observations. Because this derivation is achieved using restriction, data sets conforming to this type will inherently conform to the base data set structure as well. In fact, data structured here will be identical to data in the base data set when the time dimension is the observation dimension. This means that the data contained in this structure can be processed in exactly the same manner as the base structure. + + + + + + + + + + + + Series contains a collection of observations that share a common key (set of dimension values). The key of a series is every dimension defined in the data structure definition, save the time dimension. In addition to the key and observations, the series contains values for attributes which have a relationship with any dimension that is part of the series key, so long as the attribute does not specify an attachment group or also has a relationship with the time dimension. + + + + + + + + + + + TimeSeriesType defines a structure which is used to group a collection of observations which have a key in common, organised by time. The key for a series is every dimension defined in the data structure definition, save the time dimension. In addition to observations, values can be provided for attributes which are associated with the dimensions which make up this series key (so long as the attributes do not specify a group attachment or also have an relationship with the time dimension). It is possible for the series to contain only observations or only attribute values, or both. + + + + + + + + + + Obs contains an observation which shares the dimensionality of the series key. These observations are disambiguated from one another within this series by a time value. + + + + + + + + + + TimeSeriesObsType defines the structure of a time series observation. The observation must be provided a value for the time dimension. This time value should disambiguate the observation within the series in which it is defined (i.e. there should not be another observation with the same time value). The observation can contain an observed value and/or attribute values. + + + + + + + + + + Attributes contains the set of values reported for the attributes which have an association with the primary measure or the time dimension (so long as an attachment group is not also specified). + + + + + + + + + + TimeValueType is a derivation of the BaseValueType which is used to provide a value for the time dimension. Since the identifier for the time dimension is fixed, the component reference for this structure is fixed. Note that this means that it is not necessary to provide a value in an instance as the fixed value will be provided in the post validation information set. + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecific.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecific.xsd new file mode 100644 index 0000000..5b92f2a --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecific.xsd @@ -0,0 +1,12 @@ + + + + + + + + SDMX Core Structure Specific Data Namespace Module + The core structure specific data namespace module provides the common framework to be used for all data structure definition-specific schemas for data exchange, update, and revisions. It is intended for bilateral use. This forms the basis for all sets of namespace modules created and maintained by those who create data structure definition-specific data schemas which are not maintained by SDMX. + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecificBase.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecificBase.xsd new file mode 100644 index 0000000..6fccd76 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecificBase.xsd @@ -0,0 +1,232 @@ + + + + + + + SDMX Core Base Structure Specific Data Module + The core base structure specific data module contains the descriptions of base structure specific data set format. The data set defined here describes the structure of the data set in all structure specific data messages. Any structure specific data messages must derive the data set from this format. The entire structure declared for the is data set is abstract, meaning that instances will have to be based on types derived from these structures in schemas created based on the details data structure definition. + + + + + +

DataSetType is the abstract type which defines the base structure for any data structure definition specific data set. A derived data set type will be created that is specific to a data structure definition and the details of the organisation of the data (i.e. which dimension is the observation dimension and whether explicit measures should be used). Data is organised into either a collection of series (grouped observations) or a collection of un-grouped observations. The derived data set type will restrict this choice to be either grouped or un-grouped observations. If this dimension is "AllDimensions" then the derived data set type must consist of a collection of un-grouped observations; otherwise the data set will contain a collection of series with the observations in the series disambiguated by the specified dimension at the observation level. This data set is capable of containing data (observed values) and/or documentation (attribute values) and can be used for incremental updates and deletions (i.e. only the relevant updates or deletes are exchanged). It is assumed that each series or un-grouped observation will be distinct in its purpose. For example, if series contains both data and documentation, it assumed that each series will have a unique key. If the series contains only data or only documentation, then it is possible that another series with the same key might exist, but with not with the same purpose (i.e. to provide data or documentation) as the first series.

+ +

This base type is designed such that derived types can be processed in a generic manner; it assures that data structure definition specific data will have a consistent structure. The group, series, and observation elements are unqualified, meaning that they are not qualified with a namespace in an instance. This means that in the derived data set types, the elements will always be the same, regardless of the target namespace of the schemas which defines these derived types. This allows for consistent processing of the structure without regard to what the namespace might be for the data structure definition specific schema.

+ +

The data set can contain values for attributes which do not have an attribute relationship with any data structure definition components. These attribute values will exist in XML attributes in this element based on this type (DataSet). This is specified in the content model with the declaration of anyAttributes in the "local" namespace. The derived data set type will refine this structure so that the attributes are explicit. The XML attributes will be given a name based on the attribute's identifier. These XML attributes will be unqualified (meaning they do not have a namespace associated with them). To allow for generic processing, it is required that the only unqualified XML attributes in the derived data set type (outside of the standard data set attributes) be for attributes declared in the data structure definition. If additional attributes are required, these should be qualified with a namespace so that a generic application can easily distinguish them as not being meant to represent a data structure definition attribute.

+
+
+ + + + + + DataProvider contains a reference to the provider for the data set. + + + + + Group contains a references to a defined group in the data structure definition along with its key (if necessary) and values for the attributes which are associated with the group. An attribute is associated to a group by either an explicit group relationship or by a group attachment when the attribute has a relationship with a dimension which is a member of this group. + + + + + + Series contains a collection of observations that share a common key (set of dimension values). The key of a series is every dimension defined in the data structure definition, save the dimension at the observation level. In addition to the key and observations, the series contains values for attributes which have a relationship with any dimension that is part of the series key, so long as the attribute does not specify an attachment group or also has a relationship with the dimension declared to be at the observation level. + + + + + Obs is an un-grouped observation. This observation has a key which is a set of values for all dimensions declared in the data structure definition. In addition to the key, the value of the observation can be provided along with values for all attributes which have an association with the primary measure or any dimension (so long as it does not specify a group attachment). + + + + + + + + The REPORTING_YEAR_START_DAY attribute is an explict attribute for the reporting year start day, which provides context to the time dimension when its value contains a reporting period (e.g. 2010-Q1). This attribute is used to state the month and day that the reporting year begins (e.g. --07-01 for July 1st). In the absence of an explicit value provided in this attribute, all reporting period values will be assumed to be based on a reporting year start day of January 1. This is declared in the base schema since it has a fixed identifier and representation. The derived data set type may either require or prohibit this attribute, depending on whether the data structure declared the reporting year start day attribute and if so, the attribute relationship and assignment status assigned to it. + + + + + +
+ + + + +

GroupType is the abstract type which defines a structure which is used to communicate attribute values for a group defined in a data structure definition. The group can consist of either a subset of the dimensions defined by the data structure definition, or an association to an attachment constraint, which in turn defines key sets to which attributes can be attached. In the case that the group is based on an attachment constraint, only the identification of group is provided. It is expected that a system which is processing this will relate that identifier to the key sets defined in the constraint and apply the values provided for the attributes appropriately.

+ +

Data structure definition schemas will drive types based on this for each group defined in the data structure definition. Both the dimension values which make up the key (if applicable) and the attribute values associated with the group will be represented with XML attributes. This is specified in the content model with the declaration of anyAttributes in the "local" namespace. The derived group type will refine this structure so that the attributes are explicit. The XML attributes will be given a name based on the attribute's identifier. These XML attributes will be unqualified (meaning they do not have a namespace associated with them). The dimension XML attributes will be required while the attribute XML attributes will be optional. To allow for generic processing, it is required that the only unqualified XML attributes in the derived group type be for the group dimensions and attributes declared in the data structure definition. If additional attributes are required, these should be qualified with a namespace so that a generic application can easily distinguish them as not being meant to represent a data structure definition dimension or attribute.

+
+
+ + + + + The type attribute reference the identifier of the group as defined in the data structure definition. This is optional, but derived group types will provide a fixed value for this so that it always available in the post validation information set. This allows the group to be processed in a generic manner. + + + + + The REPORTING_YEAR_START_DAY attribute is an explict attribute for the reporting year start day, which provides context to the time dimension when its value contains a reporting period (e.g. 2010-Q1). This attribute is used to state the month and day that the reporting year begins (e.g. --07-01 for July 1st). In the absence of an explicit value provided in this attribute, all reporting period values will be assumed to be based on a reporting year start day of January 1. This is declared in the base schema since it has a fixed identifier and representation. The derived group types may either require or prohibit this attribute, depending on whether the data structure declared the reporting year start day attribute and if so, the attribute relationship and assignment status assigned to it. + + + + + +
+ + + + +

SeriesType is the abstract type which defines a structure which is used to group a collection of observations which have a key in common. The key for a series is every dimension defined in the data structure definition, save the dimension declared to be at the observation level for this data set. In addition to observations, values can be provided for attributes which are associated with the dimensions which make up this series key (so long as the attributes do not specify a group attachment or also have an relationship with the observation dimension). It is possible for the series to contain only observations or only attribute values, or both.

+ +

Data structure definition schemas will drive a type based on this that is specific to the data structure definition and the variation of the format being expressed in the schema. Both the dimension values which make up the key and the attribute values associated with the key dimensions will be represented with XML attributes. This is specified in the content model with the declaration of anyAttributes in the "local" namespace. The derived series type will refine this structure so that the attributes are explicit. The XML attributes will be given a name based on the attribute's identifier. These XML attributes will be unqualified (meaning they do not have a namespace associated with them). The dimension XML attributes will be required while the attribute XML attributes will be optional. To allow for generic processing, it is required that the only unqualified XML attributes in the derived group type be for the series dimensions and attributes declared in the data structure definition. If additional attributes are required, these should be qualified with a namespace so that a generic application can easily distinguish them as not being meant to represent a data structure definition dimension or attribute.

+
+
+ + + + + + + + The TIME_PERIOD attribute is an explict attribute for the time dimension. This is declared in the base schema since it has a fixed identifier and representation. The derived series type will either require or prohibit this attribute, depending on whether time is the observation dimension. If the time dimension specifies a more specific representation of time the derived type will restrict the type definition to the appropriate type. + + + + + The REPORTING_YEAR_START_DAY attribute is an explict attribute for the reporting year start day, which provides context to the time dimension when its value contains a reporting period (e.g. 2010-Q1). This attribute is used to state the month and day that the reporting year begins (e.g. --07-01 for July 1st). In the absence of an explicit value provided in this attribute, all reporting period values will be assumed to be based on a reporting year start day of January 1. This is declared in the base schema since it has a fixed identifier and representation. The derived series type may either require or prohibit this attribute, depending on whether the data structure declared the reporting year start day attribute and if so, the attribute relationship and assignment status assigned to it. + + + + + +
+ + + + +

ObsType is the abstract type which defines the structure of a grouped or un-grouped observation. The observation must be provided a key, which is either a value for the dimension which is declared to be at the observation level if the observation is grouped, or a full set of values for all dimensions in the data structure definition if the observation is un-grouped. This key should disambiguate the observation within the context in which it is defined (e.g. there should not be another observation with the same dimension value in a series). The observation can contain an observed value and/or attribute values.

+ +

Data structure definition schemas will drive a type or types based on this that is specific to the data structure definition and the variation of the format being expressed in the schema. The dimension value(s) which make up the key and the attribute values associated with the key dimension(s) or the primary measure will be represented with XML attributes. This is specified in the content model with the declaration of anyAttributes in the "local" namespace. The derived observation type will refine this structure so that the attributes are explicit. The XML attributes will be given a name based on the attribute's identifier. These XML attributes will be unqualified (meaning they do not have a namespace associated with them). The dimension XML attribute(s) will be required while the attribute XML attributes will be optional. To allow for generic processing, it is required that the only unqualified XML attributes in the derived observation type be for the observation dimension(s) and attributes declared in the data structure definition. If additional attributes are required, these should be qualified with a namespace so that a generic application can easily distinguish them as not being meant to represent a data structure definition dimension or attribute.

+ +

If the data structure definition specific schema requires that explicit measures be used (only possible when the measure dimension is specified at the observation), then there will be types derived for each measure defined by the measure dimension. In this case, the types will be specific to each measure, which is to say that the representation of the primary measure (i.e. the observed value) will be restricted to that which is specified by the specific measure.

+
+
+ + + + + The type attribute is used when the derived format requires that explicit measure be used. In this case, the derived type based on the measure will fix this value to be the identification of the measure concept. This will not be required, but since it is fixed it will be available in the post validation information set which will allow for generic processing of the data. If explicit measures are not used, then the derived type will prohibit the use of this attribute. + + + + + The TIME_PERIOD attribute is an explicit attribute for the time dimension. This is declared in the base schema since it has a fixed identifier and representation. The derived series type will either require or prohibit this attribute, depending on whether time is the observation dimension. If the time dimension specifies a more specific representation of time the derived type will restrict the type definition to the appropriate type. + + + + + The REPORTING_YEAR_START_DAY attribute is an explict attribute for the reporting year start day, which provides context to the time dimension when its value contains a reporting period (e.g. 2010-Q1). This attribute is used to state the month and day that the reporting year begins (e.g. --07-01 for July 1st). In the absence of an explicit value provided in this attribute, all reporting period values will be assumed to be based on a reporting year start day of January 1. This is declared in the base schema since it has a fixed identifier and representation. The derived observation type may either require or prohibit this attribute, depending on whether the data structure declared the reporting year start day attribute and if so, the attribute relationship and assignment status assigned to it. + + + + + The OBS_VALUE attribute is an explicit attribute for the primary measure, which is intended to hold the value for the observation. This is declared in the base schema since it has a fixed identifier. This attribute is un-typed, since the representation of the observed value can vary widely. Derived types will restrict this to be a type based on the representation of the primary measure. In the case that an explicit measure is used, the derived type for a given measure might further restrict the type of the primary measure to be more specific to the core representation for the measure concept. Note that it is required that in the case of multiple measures being used, that the representation of the primary measure is broad enough to handle the various representations of the measure concepts. + + + + + +
+ + + + DataScopeType is an enumeration of the possible validity scopes for a data set. These scopes indicate the level at which the data is stated to be valid. + + + + + The data set conforms simply to the data structure definition as it is defined, without regard to any constraints. + + + + + The data set conforms to the known allowable content constraints applied to the data structure definition. + + + + + The data set conforms to the known allowable content constraints applied to the dataflow. + + + + + The data set conforms to the known allowable content constraints applied to the provision agreement. + + + + + + + + The SetAttributeGroup defines a common set of attributes pertaining to any data set. The attributes are qualified, so that they will be easily distinguished from attributes that are specific to the data structure. Note that many of these attributes are duplications of fields available in the header of the data messages. The reason for this is to allow the header values to be overridden at the data set level when a message contains more than one data set. If an attribute here does not have a value, then the value from the header is applied to the data set. + + + + The structureRef contains a reference to a structural specification in the header of a data or reference metadata message. The structural specification details which structure the data or reference metadata conforms to, as well as providing additional information such as how the data is structure (e.g. which dimension occurs at the observation level for a data set). + + + + + The setID provides an identification of the data or metadata set. + + + + + The action attribute indicates whether the file is appending, replacing, or deleting. + + + + + The reportingBeginDate indicates the inclusive start time of the data reported in the data or metadata set. + + + + + The reportingEndDate indicates the inclusive end time of the data reported in the data or metadata set. + + + + + The validFromDate indicates the inclusive start time indicating the validity of the information in the data or metadata set. + + + + + The validToDate indicates the inclusive end time indicating the validity of the information in the data or metadata set. + + + + + The publicationYear holds the ISO 8601 four-digit year. + + + + + The publicationPeriod specifies the period of publication of the data or metadata in terms of whatever provisioning agreements might be in force (i.e., "Q1 2005" if that is the time of publication for a data set published on a quarterly basis). + + + + + The dataScope attribute indicates the scope at which the data is meant to be validated. These scopes are hierarchical and are (from the top down); DataStructure, ConstrainedDataStructure, Dataflow, and ProvisionAgreement. the hierarchy of these scopes represent the cascading level of constraints, which can restrict the valid values for components. For example, a data structure defines a dimension with a coded representation. A data flow might have a constraint associated with it which further restricts the values allowed from the referenced code list to a subset of the values allowed by the data structure definition. A provision agreement that is based on the dataflow might also have a constraint, which further restricts the subset of the codelist from the dataflow. Therefore, the allowed content becomes stricter lower in the hierarchy. Data that is given a scope of one value is stated to be valid at that level and all levels below it. Therefore, this scope serves to state that data that is meant to be structured simply against the data structure definition is not meant to be validated against the a dataflow, where constraints might be applied. + + + + +
\ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecificTimeSeries.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecificTimeSeries.xsd new file mode 100644 index 0000000..ea8c722 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecificTimeSeries.xsd @@ -0,0 +1,69 @@ + + + + + + + + SDMX Core Time Series Structure Specific Data Module + The core time series structure specific data module contains the descriptions of a derivation of the base structure specific data set format which only allows for data organised as time series. A data set structure specific according to the data set defined here is a valid base structure specific data set, and can be processed using the same rules as those for the base format. The difference in this structure is that the data is assured to be organised as time series. This allows for variations of the structure specific data message which restrict the data to only be formatted as time series. The entire structure declared for the is data set is abstract, meaning that instances will have to be based on types derived from these structures in schemas created based on the details data structure definition. + + + + + TimeSeriesDataSetType is the abstract type which defines the base structure for any data structure definition specific time series based data set. A derived data set type will be created that is specific to a data structure definition. Unlike the base format, only one variation of this is allowed for a data structure definition. This variation is the time dimension as the observation dimension. Data is organised into a collection of time series. Because this derivation is achieved using restriction, data sets conforming to this type will inherently conform to the base data set structure as well. In fact, data structure specific here will be identical to data in the base data set when the time dimension is the observation dimension, even for the derived data set types. This means that the data contained in this structure can be processed in exactly the same manner as the base structure. The same rules for derivation as the base data set type apply to this specialized data set. + + + + + + + + + + + + + + + + + + + + TimeSeriesType defines an abstract structure which is used to group a collection of observations which have a key in common, organised by time. The key for a series is every dimension defined in the data structure definition, save the time dimension. In addition to observations, values can be provided for attributes which are associated with the dimensions which make up this series key (so long as the attributes do not specify a group attachment or also have an relationship with the time dimension). It is possible for the series to contain only observations or only attribute values, or both. The same rules for derivation as the base series type apply to this specialized series. + + + + + + + + + + + + + + + + TimeSeriesObsType defines the abstract structure of a time series observation. The observation must be provided a value for the time dimension. This time value should disambiguate the observation within the series in which it is defined (i.e. there should not be another observation with the same time value). The observation can contain an observed value and/or attribute values. The same rules for derivation as the base observation type apply to this specialized observation. + + + + + + + + + + The TIME_PERIOD attribute is an explicit attribute for the time dimension. This is declared in the base schema since it has a fixed identifier and representation. Since this data is structured to be time series only, this attribute is always required. If the time dimension specifies a more specific representation of time the derived type will restrict the type definition to the appropriate type. + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMessage.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMessage.xsd new file mode 100644 index 0000000..b179a8c --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMessage.xsd @@ -0,0 +1,1182 @@ + + + + + + + + + + + + + + + + SDMX Message Namespace Module + The message namespace module contains the common message constructs, including the common header information which is used with all other SDMX-ML namespace modules. + + + + + + + MessageType is an abstract type which is used by all of the messages, to allow inheritance of common features. Every message consists of a mandatory header, followed by optional payload (which may occur multiple times), and finally an optional footer section for conveying error, warning, and informational messages. + + + + + + + + + + + + + Structure is a message that contains structural metadata. It may contain any of the following; categorisations, category schemes, code lists, concepts (concept schemes), constraints (attachment and content) data flows, hierarchical code lists, metadata flows, metadata structure definitions, organisation schemes, processes, reporting taxonomies, and structure sets. + + + + + + StructureType defines the contents of a structure message. The payload is optional since this message may be returned from a web service with only information in the footer. + + + + + + + + + + + + + + + + + GenericData is used to convey data in a non data structure specific form. Data sets in this message will be each have a related structure specification in the header, which states the data structure the data conforms to and how the data is organised (i.e. the observation dimension). + + + + + + GenericDataType defines the contents of a generic data message. + + + + + + + + + + + + + + + GenericTimeSeriesData is a special derivation of the generic data message which only allows for time series oriented date (i.e. the observation dimension must be time). Although this is a different message, the content of this message will be exactly the same as a generic data message that specifies time as the observation dimension; therefore no additional processing requirements are necessary. This message is intended to only be used when it is necessary to restrict an exchange to being only time series based data. + + + + + + GenericTimeSeriesDataType defines the structure of the generic time series data message. + + + + + + + + + + + + + + + StructureSpecificData is used to convey data structure specific according to data structure definition. The payload of this message (i.e. the data sets) will be based on XML schemas which are specific to the data structure definition and the orientation (i.e. the observation dimension) of the data. + + + + + + StructureSpecificDataType defines the structure of the structure specific data message. Note that the data set payload type is abstract, and therefore it will have to be assigned a type in an instance. This type must be derived from the base type referenced. This base type defines a general structure which can be followed to allow for generic processing of the data even if the exact details of the data structure specific format are not known. + + + + + + + + + + + + + + + StructureSpecificTimeSeriesData is a special derivation of the structure specific data message which only allows for time series oriented date (i.e. the observation dimension must be time). Although this is a different message, the content of this message will be exactly the same as a structure specific data message that specifies time as the observation dimension; therefore no additional processing requirements are necessary. This message is intended to only be used when it is necessary to restrict an exchange to being only time series based data. + + + + + + StructureSpecificTimeSeriesDataType defines the structure of the structure specific time series data message. + + + + + + + + + + + + + + + + + GenericMetadata contains reported metadata in a format which supports any metadata structure definition. + + + + + + GenericMetadataType defines the contents of a generic metadata message. + + + + + + + + + + + + + + + StructureSpecificMetadata contains reported metadata in a format which is specific to the metadata structure definitions which define the structure of the metadata being reported. This format allows for validation of the metadata against the intended structure. Note that the each metadata set provided will be based on a metadata structure specific schema. + + + + + StructureSpecificMetadataType defines the structure of a structure specific metadata message. Note that the metadata set payload type is abstract, and therefore it will have to be assigned a type in an instance. This type must be derived from the base type referenced. This base type defines a general structure which can be followed to allow for generic processing of the data even if the exact details of the data structure specific format are not known. + + + + + + + + + + + + + + + + + + + StructureSpecificDataQuery is used to query SDMX compliant databases or web services for structure specific data. + + + + + + DataQueryType defines the structure of a data query message. + + + + + + + + + + + + + + GenericDataQuery is used to query SDMX compliant databases or web services for generic data. This is actually a specialization of the structured data query, and therefore can be processed in the same manner. + + + + + + DataQueryType defines the structure of a generic data query message. + + + + + + + + + + + + + + GenericTimeSeriesDataQuery is used to query SDMX compliant databases or web services for time series only generic data. This is actually a specialization of the generic data query, and therefore can be processed in the same manner. This message is intended to only be used when it is necessary to restrict an exchange to being only time series based data. + + + + + + GenericTimeSeriesDataQueryType defines the structure of a time series generic data query message. + + + + + + + + + + + + + + StructureSpecificTimeSeriesDataQuery is used to query SDMX compliant databases or web services for time series only structure specific data. This is actually a specialization of the structure specific data query, and therefore can be processed in the same manner. This message is intended to only be used when it is necessary to restrict an exchange to being only time series based data. + + + + + + StructureSpecificTimeSeriesDataQueryType defines the structure of a time series generic data query message. + + + + + + + + + + + + + + GenericMetadataQuery is used to query SDMX compliant databases or web services for generic format reference metadata. + + + + + + StructureSpecificMetadataQuery is used to query SDMX compliant databases or web services for metadata structure specific reference metadata. + + + + + + MetadataQueryType defines the structure of a reference metadata query message. + + + + + + + + + + + + + + DataSchemaQuery is used to query SDMX compliant databases or web services for data structure specific schemas for the purpose of validating structured data. + + + + + + DataSchemaQueryType defines the structure of a data schema query message. + + + + + + + + + + + + + + MetadataSchemaQuery is used to query SDMX compliant databases or web services for metadata structure specific schemas for the purpose of validating structured metadata. + + + + + + MetadataSchemaQueryType defines the structure of a metadata schema query message. + + + + + + + + + + + + + + StructuresQuery is used to query SDMX compliant databases or web services for any structures based on simple maintainable object properties (e.g. all objects maintained by a maintenance agency). + + + + + + StructuresQueryType defines the structure of a structures query message. + + + + + + + + + + + + + + DataflowQuery is used to query SDMX compliant databases or web services for dataflows. + + + + + + DataflowQueryType defines the structure of a dataflow query message. + + + + + + + + + + + + + + MetadataflowQuery is used to query SDMX compliant databases or web services for metadata flows. + + + + + + MetadataflowQueryType defines the structure of a metadata flow query message. + + + + + + + + + + + + + + DataStructureQuery is used to query SDMX compliant databases or web services for data structures definitions. + + + + + + KeyFamilyQueryType defines the structure of a data structure query message. + + + + + + + + + + + + + + MetadataStructureQuery is used to query SDMX compliant databases or web services for metadata structure definitions. + + + + + + MetadataStructureQueryType defines the structure of a metadata structure query message. + + + + + + + + + + + + + + CategorySchemeQuery is used to query SDMX compliant databases or web services for category schemes. + + + + + + CategorySchemeQueryType defines the structure of a category scheme query message. + + + + + + + + + + + + + + ConceptSchemeQuery is used to query SDMX compliant databases or web services for concept schemes. + + + + + + ConceptSchemeQueryType defines the structure of a concept scheme query message. + + + + + + + + + + + + + + CodelistQuery is used to query SDMX compliant databases or web services for codelists. + + + + + + CodelistQueryType defines the structure of a codelist query message. + + + + + + + + + + + + + + HierarchicalCodelistQuery is used to query SDMX compliant databases or web services for hierarchical codelists. + + + + + + HierarchicalCodelistQueryType defines the structure of a hierarchical codelist query message. + + + + + + + + + + + + + + OrganisationSchemeQuery is used to query SDMX compliant databases or web services for organisation schemes. + + + + + + OrganisationSchemeQueryType defines the structure of an organisation scheme query message. + + + + + + + + + + + + + + ReportingTaxonomyQuery is used to query SDMX compliant databases or web services for reporting taxonomies. + + + + + + ReportingTaxonomyQueryType defines the structure of a reporting taxonomy query message. + + + + + + + + + + + + + + StructureSetQuery is used to query SDMX compliant databases or web services for structure sets. + + + + + + StructureSetQueryType defines the structure of a structure set query message. + + + + + + + + + + + + + + ProcessQuery is used to query SDMX compliant databases or web services for processes. + + + + + + CategorizationQueryType defines the structure of a categorization query message. + + + + + + + + + + + + + + CategorisationQuery is used to query SDMX compliant databases or web services for categorisations. + + + + + + CategorisationQueryType defines the structure of a categorisation query message. + + + + + + + + + + + + + + ProvisionAgreementQuery is used to query SDMX compliant databases or web services for provision agreements. + + + + + + ProvisionAgreementQueryType defines the structure of a provision agreement query message. + + + + + + + + + + + + + + ConstraintQuery is used to query SDMX compliant databases or web services for constraints. + + + + + + ConstraintQueryType defines the structure of a constraint query message. + + + + + + + + + + + + + + TransformationSchemeQuery is used to query SDMX compliant databases or web services for transformation schemes. + + + + + + TransformationSchemeQueryType defines the structure of a transformation scheme query message. + + + + + + + + + + + + + + VtlMappingSchemeQuery is used to query SDMX compliant databases or web services for VTL mapping schemes. + + + + + + VtlMappingSchemeQueryType defines the structure of a VTL mappings scheme query message. + + + + + + + + + + + + + + NamePersonalisationSchemeQuery is used to query SDMX compliant databases or web services for name personalisation schemes. + + + + + + NamePersonalisationSchemeQueryType defines the structure of a name personalisation scheme query message. + + + + + + + + + + + + + + RulesetSchemeQuery is used to query SDMX compliant databases or web services for ruleset schemes. + + + + + + RulesetSchemeQueryType defines the structure of a ruleset scheme query message. + + + + + + + + + + + + + + UserDefinedOperatorSchemeQuery is used to query SDMX compliant databases or web services for user defined schemes. + + + + + + UserDefinedOperatorSchemeQueryType defines the structure of a user defined operator scheme query message. + + + + + + + + + + + + + + CustomTypeSchemeQuery is used to query SDMX compliant databases or web services for custom type schemes. + + + + + + CustomTypeSchemeQueryType defines the structure of a custom type scheme query message. + + + + + + + + + + + + + + + + Error is used to communicate that an error has occurred when responding to a request in an non-registry environment. The content will be a collection of error messages. + + + + + + ErrorType describes the structure of an error response. + + + + + ErrorMessage contains the error message. It can occur multiple times to communicate message for multiple errors, or to communicate the error message in parallel languages. If both messages for multiple errors and parallel language messages are used, then each error message should be given a code in order to distinguish message for unique errors. + + + + + + + + + + BaseHeaderType in an abstract base type that defines the basis for all message headers. Specific message formats will refine this + + + + + ID identifies an identification for the message, assigned by the sender. + + + + + Test indicates whether the message is for test purposes or not. + + + + + Prepared is the date the message was prepared. + + + + + Sender is information about the party that is transmitting the message. + + + + + Receiver is information about the party that is the intended recipient of the message. + + + + + Name provides a name for the transmission. Multiple instances allow for parallel language values. + + + + + Structure provides a reference to the structure (either explicitly or through a structure usage reference) that describes the format of data or reference metadata. In addition to the structure, it is required to also supply the namespace of the structure specific schema that defines the format of the data/metadata. For cross sectional data, additional information is also required to state which dimension is being used at the observation level. This information will allow the structure specific schema to be generated. For generic format messages, this is used to simply reference the underlying structure. It is not mandatory in these cases and the generic data/metadata sets will require this reference explicitly. + + + + + DataProvider identifies the provider of the data for a data/reference metadata message. + + + + + DataSetAction code provides a code for determining whether the enclosed message is an Update or Delete message (not to be used with the UtilityData message). + + + + + DataSetID provides an identifier for a contained data set. + + + + + Extracted is a time-stamp from the system rendering the data. + + + + + ReportingBegin provides the start of the time period covered by the message (in the case of data). + + + + + ReportingEnd provides the end of the time period covered by the message (in the case of data). + + + + + EmbargoDate holds a time period before which the data included in this message is not available. + + + + + Source provides human-readable information about the source of the data. + + + + + + + + StructureHeaderType defines the structure for structural metadata messages. + + + + + + + + + + + + + + + + + + + GenericDataHeaderType defines the header structure for a generic data message. + + + + + + + + + + + + + + + + + + + + + + + + + + + GenericTimeSeriesDataHeaderType defines the header structure for a time series only generic data message. + + + + + + + + + + + + + + + + + + + + + + + + + + + StructureSpecificDataHeaderType defines the header structure for a structure specific data message. + + + + + + + + + + + + + + + + + + + + + + + + + + + StructureSpecificTimeSeriesDataHeaderType defines the header structure for a time series only structure specific data message. + + + + + + + + + + + + + + + + + + + + + + + + + + + GenericMetadataHeaderType defines the header format for generic reference metadata. + + + + + + + + + + + + + + + + + + + + + + + + StructureSpecificMetadataHeaderType defines the header format for metadata structure definition specific reference metadata messages. + + + + + + + + + + + + + + + + + + + + + + + + BasicHeaderType defines the most basic header information used in simple message exchanges. + + + + + + + + + + + + + + + + + PartyType defines the information which is sent about various parties such as senders and receivers of messages. + + + + + Name is a human-readable name of the party. + + + + + Contact provides contact information for the party in regard to the transmission of the message. + + + + + + The id attribute holds the identification of the party. + + + + + + + SenderType extends the basic party structure to add an optional time zone declaration. + + + + + + + Timezone specifies the time zone of the sender, and if specified can be applied to all un-time zoned time values in the message. In the absence of this, any dates without time zone are implied to be in an indeterminate "local time". + + + + + + + + + + ContactType provides defines the contact information about a party. + + + + + Name contains a human-readable name for the contact. + + + + + Department is designation of the organisational structure by a linguistic expression, within which the contact person works. + + + + + Role is the responsibility of the contact person with respect to the object for which this person is the contact. + + + + + + Telephone holds the telephone number for the contact person. + + + + + Fax holds the fax number for the contact person. + + + + + X400 holds the X.400 address for the contact person. + + + + + URI holds an information URL for the contact person. + + + + + Email holds the email address for the contact person. + + + + + + + + + Provides a union type of xs:date and xs:dateTime for the header fields in the message. + + + + + diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMessageFooter.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMessageFooter.xsd new file mode 100644 index 0000000..d0baed6 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMessageFooter.xsd @@ -0,0 +1,58 @@ + + + + + + + + + + Footer is used to communicate information such as error and warnings after the payload of a message. + + + + + + FooterType describes the structure of a message footer. The footer is used to convey any error, information, or warning messages. This is to be used when the message has payload, but also needs to communicate additional information. If an error occurs and no payload is generated, an Error message should be returned. + + + + + Message contains a single error, information, or warning message. A code is provided along with an optional severity. The text of the message can be expressed in multiple languages. + + + + + + + + FooterMessageType defines the structure of a message that is contained in the footer of a message. It is a status message that have a severity code of Error, Information, or Warning added to it. + + + + + + + + + + + + + Error indicates the status message coresponds to an error. + + + + + Warning indicates that the status message corresponds to a warning. + + + + + Information indicates that the status message corresponds to an informational message. + + + + + + diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMetadataGeneric.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMetadataGeneric.xsd new file mode 100644 index 0000000..793898e --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMetadataGeneric.xsd @@ -0,0 +1,175 @@ + + + + + + + SDMX Generic Metadata Namespace Module + The generic metadata namespace module describes a generic format for the reporting of reference metadata, regardless of the underlying metadata structure definition. + + + + + MetadataSetType describes the structure for a metadata set, which contains a collection of reported metadata against a set of values for a given full or partial target identifier, as described in a metadata structure definition. The metadata set may contain reported metadata for multiple report structures defined in a metadata structure definition. + + + + + + + + DataProviderReference provides a references to an organisation with the role of data provider that is providing this metadata set. + + + + + Report contains the details of a the reported metadata, including the identification of the target and the report attributes. + + + + + + + + + + + + ReportType contains a set of report attributes and identifies a target objects] to which they apply. + + + + + + + Target contains a set of target reference values which when taken together, identify the object or objects to which the reported metadata apply. + + + + + + + + + AttributeSet contains the reported metadata attribute values for the reported metadata. + + + + + + The id attribute holds the identifier of the report structure as defined in the metadata structure definition. This identifies the report structure which defines the structure of metadata that is being reported. + + + + + + + + + TargetType defines the structure of a target. It contains a set of target reference values which when taken together, identify the object or objects to which the reported metadata apply. + + + + + ReferenceValue contains a value for a target reference object reference. When this is taken with its sibling elements, they identify the object or objects to which the reported metadata apply. The content of this will either be a reference to an identifiable object, a data key, a reference to a data set, or a report period. + + + + + + The id attribute holds the identifier of the metadata target as defined in the metadata structure definition. This identifies the metadata target of the report structure that identifies the target object(s) of the reported metadata. + + + + + + + ReferenceValueType defines the structure of a target object reference value. A target reference value will either be a reference to an identifiable object, a data key, a reference to a data set, or a report period. + + + + + ObjectReference provides a reference to an identifiable object in the SDMX information model. An identifiable object target will utilize this option as the representation of the target reference value. + + + + + ObjectReference provides a set of dimension references and values for those dimension for the purpose of reporting metadata against a set of data. A key descriptor values target will utilize this option as the representation of the target reference value. + + + + + DataSetReference provides a reference to a data set for the purpose of reporting metadata against the data. A data set target will utilize this option as the representation of the target reference value. + + + + + ConstraintContentReference provides a reference to an attachment constraint for the purpose of reporting metadata against the data identified in the key sets and/or cube regions identified by the constraint. A constraint target will utilize this option as the representation of the target reference value. + + + + + ReportPeriod provides a report period for the purpose of qualifying the target reporting period of reported metadata. A report period target will utilize this option as the representation of the target reference value. + + + + + + The id attribute holds the identifier of the target reference object as defined in the metadata structure definition. This identifies the target reference of the metadata target that identifes one of the target references, that when taken together, identify the target of the reported metadata. + + + + + + + AttributeSetType defines the structure for a collection of reported metadata attributes. + + + + + ReportedAttribute provides the details of a reported attribute, including a value and/or child reported attributes. + + + + + + + + ReportedAttributeType defines the structure for a reported metadata attribute. A value for the attribute can be supplied as either a single value, or multi-lingual text values (either structured or unstructured). An optional set of child metadata attributes is also available if the metadata attribute definition defines nested metadata attributes. + + + + + + + + Text is used to supply parallel multi-lingual textual values for the reported metadata attribute. This will be used if the text format of the metadata attribute has a type of string and the multi-lingual value is set to true. + + + + + StructuredText is used to supply parallel multi-lingual structured (as XHTML) textual values for the reported metadata attribute. This will be used if the text format of the metadata attribute has a type of XHTML and the multi-lingual value is set to true. + + + + + + AttributeSet contains the reported metadata attribute values for the child metadata attributes. + + + + + + The id attribute identifies the metadata attribute that the value is being reported for. + + + + + The value attribute holds any simple value for the metadata attribute. + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMetadataStructureSpecific.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMetadataStructureSpecific.xsd new file mode 100644 index 0000000..55d705c --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXMetadataStructureSpecific.xsd @@ -0,0 +1,213 @@ + + + + + + + SDMX Structure Specific Metadata Namespace Module + The structure specific metadata namespace module provides the common framework to be used for all metadata structure definition-specific schemas for reference metadata reporting. This forms the basis for all sets of namespace modules created and maintained by those who create metadata structure definition-specific reference metadata schemas which are not maintained by SDMX. + + + + + MetadataSetType is an abstract base type the forms the basis for a metadata structure specific metadata set. It is restricted by the metadata structure definition specific schema to meet its needs. + + + + + + + + >DataProviderReference provides a references to an organisation with the role of data provider that is providing this metadata set. + + + + + Report contains the details of a the reported metadata, including the identification of the target and the report attributes. This element is unqualified so that the metadata structure definition specific schema can refine the type of the element such that it requires types built according to the metadata structure definition. This allows the metadata structure definition to validate the structure of the reported metadata against the metadata structure definition while still allowing the content to be processed in a generic manner. + + + + + + + + + + + ReportType is an abstract base type the forms the basis for a metadata structure definition specific report, based on the defined report structures. This type is restricted in the metadata structure definition specific schema so that the Target and AttributeSet conform to the prescribed report structure. + + + + + + + Target contains a set of target reference values which when taken together, identify the object or objects to which the reported metadata apply. This element is unqualified so that the metadata structure definition specific schema can refine the type of the element such that the references values can be validated against those defined in the metadata targets for the report structure. + + + + + AttributeSet contains the reported metadata attribute values for the reported metadata. This element is unqualified and un-typed so that it can refined by the metadata structure definition specific schema to validate that the reported metadata attributes conform to those prescribed by the report structure. The content of this must be element only, and these elements must always represent a reported attribute. Since this can not be strictly enforced in XML Schema, additional steps have been added to make generic processing of this element simpler. When processing this element, any element found with the attribute isMetadataAttribute in this target namespace is assumed to be a reported metadata attribute and can be processed as such. + + + + + + The id attribute holds the identifier of the report structure as defined in the metadata structure definition. This identifies the report structure which defines the structure of metadata that is being reported. This is optional and not expected to be supplied as the metadata structure definition specific schema will specify a fixed value such that the reference to the report structure will always be available if required for processing. + + + + + + + + + TargetType is an abstract base type that forms the basis of a the metadata report's metadata target value. This type is restricted in the metadata structure definition specific schema so that the ReferenceValue elements conform to the targets specified in the metadata target defined in the metadata structure definition. + + + + + ReferenceValue contains a value for a target reference. When this is taken with its sibling elements, they identify the object or objects to which the reported metadata apply. The content of this will either be a reference to an identifiable object, a data key, a reference to a data set, or a report period. This element is unqualified so that the metadata structure definition specific schema can refine the type of the element such that value can be validated against the format defined in the metadata structure definition. + + + + + + The id attribute holds the identifier of the metadata target as defined in the metadata structure definition. This identifies the metadata target of the report structure that identifies the target object(s) of the reported metadata. This is optional and not expected to be supplied as the metadata structure definition specific schema will specify a fixed value such that the reference to the metadata target will always be available if required for processing. + + + + + + + ReferenceValueType is an abstract base type that forms the basis of a target reference value. A target reference value will either be a reference to an identifiable object, a data key, a reference to a data set, or a report period. The choice of these options will be refined to only one according to the definition of the target in the metadata structure definition. + + + + + ObjectReference provides a reference to an identifiable object in the SDMX information model. An identifiable object target will utilize this option as the representation of the target reference value. This element is unqualified so that the metadata structure definition specific schema can refine the type of the element such that the type of reference is valid according to the object type specified in the identifiable object target in the metadata structure definition. At the very least, the reference will be specific to the type of object being referenced so that a complete set of reference fields must be provided. In cases where an item object is restricted to be from a particular scheme, this type will be further restricted so that only a valid item reference can be supplied. The structure of this reference is such that it can be generically processed without needing to know what the intended target object type is prior to processing, as this information is part of the reference. + + + + + ObjectReference provides a set of dimension references and values for those dimension for the purpose of reporting metadata against a set of data. A key descriptor values target will utilize this option as the representation of the target reference value. It is not expect that the metadata structure definition specific schema would refine this, but none the less, it is an unqualified element. + + + + + DataSetReference provides a reference to a data set for the purpose of reporting metadata against the data. A data set target will utilize this option as the representation of the target reference value. + + + + + ConstraintContentReference provides a reference to an attachment constraint for the purpose of reporting metadata against the data identified in the key sets and/or cube regions identified by the constraint. A constraint target will utilize this option as the representation of the target reference value. + + + + + ReportPeriod provides a report period for the purpose of qualifying the target reporting period of reported metadata. A report period target will utilize this option as the representation of the target reference value. It is not expect that the metadata structure definition specific schema would refine this, but none the less, it is an unqualified element. This element is unqualified so that the metadata structure definition specific schema can refine the type of the element such that the specific type of time value prescribed in the metadata structure definition can be validated. + + + + + + The id attribute holds the identifier of the target reference object reference as defined in the metadata structure definition. This identifies the target reference of the metadata target that identifes one of the target references, that when taken together, identify the target of the reported metadata. This is optional and not expected to be supplied as the metadata structure definition specific schema will specify a fixed value such that the reference to the target object definition will always be available if required for processing. + + + + + + + ReportedAttributeType is an abstract base type that forms the basis for a metadata structure specific metadata attribute. A value for the attribute can be supplied as either a single value, or multi-lingual text values (either structured or unstructured). An optional set of child metadata attributes is also available if the metadata attribute definition defines nested metadata attributes. The metadata structure definition specific schema will refine this type for each metadata attribute such that the content can be validation against what is defined in the metadata structure definition. + + + + + + + + Text is used to supply parallel multi-lingual textual values for the reported metadata attribute. This will be used if the text format of the metadata attribute has a type of string and the multi-lingual value is set to true. + + + + + StructuredText is used to supply parallel multi-lingual structured (as XHTML) textual values for the reported metadata attribute. This will be used if the text format of the metadata attribute has a type of XHTML and the multi-lingual value is set to true. If the multi-lingual flag is not set to true, it is expected that the maximum occurrence of this will be refined to be 1 in the metadata structure definition specific schema. + + + + + + AttributeSet contains the reported metadata attribute values for the child metadata attributes. This element is unqualified and un-typed so that it can refined by the metadata structure definition specific schema to validate that the reported metadata attributes conform to those prescribed by the metadata attribute definition. The content of this must be element only, and these elements must always represent a reported attribute. Since this can not be strictly enforced in XML Schema, additional steps have been added to make generic processing of this element simpler. When processing this element, any element found with the attribute isMetadataAttribute in this target namespace is assumed to be a reported metadata attribute and can be processed as such. + + + + + + The id attribute identifies the metadata attribute that the value is being reported for. This is optional and not expected to be supplied as the metadata structure definition specific schema will specify a fixed value such that the reference to the metadata attribute will always be available if required for processing. + + + + + The value attribute holds any simple value for the metadata attribute. This attribute is un-typed such that the metadata structure definition specific schema can specify any simple type according the text format / local representation defined by the metadata structure definition. + + + + + The isMetadataAttribute attribute is a fixed boolean (true) and is intended to designate to processing applications that a given element represents a reported attribute. This attribute is qualified (meaning that it will be qualified in an instance with the target namespace) to ensure that it can be properly identified by applications. The purpose of this is to allow applications to identify elements with unknown names as reported attributes so that they may process a metadata structure definition specific instance without knowledge of the underlying metadata structure definition. + + + + + + + + + The SetAttributeGroup defines a common set of attributes pertaining to any metadata set. The attributes are qualified, so that they will be easily distinguished from attributes that are specific to the metadata structure. Note that many of these attributes are duplications of fields available in the header of the metadata messages. The reason for this is to allow the header values to be overridden at the metadata set level when a message contains more than one metadata set. If an attribute here does not have a value, then the value from the header is applied to the metadata set. + + + + The structureRef contains a reference to a structural specification in the header of a data or reference metadata message. The structural specification details which structure the data or reference metadata conforms to, as well as providing additional information such as how the data is structure (e.g. which dimension occurs at the observation level for a data set). + + + + + The setID provides an identification of the data or metadata set. + + + + + The action attribute indicates whether the file is appending, replacing, or deleting. + + + + + The reportingBeginDate indicates the inclusive start time of the data reported in the data or metadata set. + + + + + The reportingEndDate indicates the inclusive end time of the data reported in the data or metadata set. + + + + + The validFromDate indicates the inclusive start time indicating the validity of the information in the data or metadata set. + + + + + The validToDate indicates the inclusive end time indicating the validity of the information in the data or metadata set. + + + + + The publicationYear holds the ISO 8601 four-digit year. + + + + + The publicationPeriod specifies the period of publication of the data or metadata in terms of whatever provisioning agreements might be in force (i.e., "Q1 2005" if that is the time of publication for a data set published on a quarterly basis). + + + + + diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQuery.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQuery.xsd new file mode 100644 index 0000000..b87ada3 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQuery.xsd @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + SDMX Query Namespace Module + The query namespace module describes the structure of the generic query message for use in web service environments. It contains constructs for querying for data, reference metadata, and structural metadata. For convenience, this module has been broken down into sub-modules for the different types of queries. + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryBase.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryBase.xsd new file mode 100644 index 0000000..ad608fb --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryBase.xsd @@ -0,0 +1,650 @@ + + + + + + + SDMX Base Query Module + The base query module provides the basic constructs of structural metadata and data/metadata queries. + + + + + + + ReturnDetailsBaseType is an abstract type that forms the basis for any query return details. + + + + The defaultLimit attribute is the suggested maximum response size in kilobytes. + + + + + >The detail attribute is used to indicate how much of the matched object should be returned. + + + + + + + + + StructureWhereQueryType is an abstract base type that serves as the basis for any structural metadata query. Concrete instances of this type are implied to be an and-query. A structural object will be returned for any object where all of the conditions are met. + + + + + + + + + + StructureReturnDetailsBaseType is an abstract base type which forms the basis of StructureReturnDetailsType. + + + + + + The detail attribute is used to indicate whether the response to the query should return the full details of matched objects, or just a subset of the information should be returned. A value of "Full" indicates that the full details of all matched objects should be returned. A value of "CompleteStub" indicates that the identification information, name, description, and annotations for the matched object should be returned. A value of "Stub" indicates that just the identification information and name should be returned for the matched objects. Note that this applies only to the object(s) matched by the query parameters. The References element has a separate field for indicating the level of detail returned for referenced objects. + + + + + + + + + StructureReturnDetailsType defines the structure of the return details for any structural metadata query. + + + + + + + References is used to communicate how objects that reference or are referenced by the object(s) being queried should be returned. + + + + + + The returnMatchedArtefact attribute indicates whether the object(s) match by the query should be returned. If this is set to false, only the reference objects from the match object(s) will be returned. + + + + + + + + + MaintainableReturnDetailsType defines the structure for the return details of a non-item scheme maintainable object. It eliminates the detail options that are specific to searching an item scheme + + + + + + + + + + + + + + + ReferencesType defines the structure for indicating which referenced objects should be returned in a structural metadata query. It is possible to return both objects which reference the object(s) matched by the query and objects referenced from the match object(s). The type(s) of reference objects to be returned consists of a choice between None, All, Default, or an explicit list of object types. + + + + + None indicates that no reference objects should be returned. + + + + + All is a convenience to indicate that the sets indicated by the ParentsAndSiblings and Descendants should be returned. + + + + + Parents is a convenience to indicate that any object that refers to the matched object should be returned. This is typically used when the query the goal is to find object refer to a set of unknown objects. + + + + + ParentsAndSiblings is a convenience to indicate that any object that refers to the matched object should be returned, along with any other objects referenced by those referring objects. + + + + + Children is a convenience to indicate that all object referred to by the matched object should be returned. + + + + + Descendants is a convenience to indicate that all object referred to by the matched object should be returned, along with any objects referenced by the referred objects, and so on. This is a deep resolution, where all outgoing references starting at the matched object are resolved. + + + + + SpecificObjects is used to enumerate specific types of object to be returned. Theses objects will either refer to or are referred by the matched object. Only the maintainable objects listed here will be returned. + + + + + + The processConstraints attribute is used to request that the query process any relevant constraints for the match object(s) in order to return only the applicable portion of any referenced codelists. A value of "true" indicates that constraints should be processed. + + + + + The detail attribute indicates the amount of detail that should be returned for reference objects. A value of "Full" indicates that the full details of all reference objects should be returned. A value of "CompleteStub" indicates that the identification information, name, description, and annotations for the reference object should be returned. A value of "Stub" indicates that just the identification information and name should be returned for the reference objects. + + + + + + + StructureReturnDetailType contains a set of enumerations that indicate how much detail should be returned for an object. + + + + + Only the identification information and name should be returned. + + + + + Identification information, name, description, and annotations should be returned. + + + + + The entire detail of the object should be returned. + + + + + For an item scheme, only the items matching the item where parameters will be returned. In the case that items are hierarchical, the entire hierarchy leading to the matched item will have to be returned. + + + + + For an item scheme, only the items matching the item where parameters, and their hierarchical child items will be returned. In the case that items are hierarchical, the entire hierarchy leading to the matched item will have to be returned. + + + + + + + + MaintainableReturnDetailType contains a sub set of the enumerations defined in the ReturnDetailType. Enumerations relating specifically to item schemes are not included + + + + + + + + + + + StructuralMetadataWhere is an abstract substitution head that forms the basis of any structural metadata query's details. This contains the actual parameters to be matched. These parameters are implicitly joined by an "and" connector (i.e. each of the parameters must be matched in order to satisfy the query). If it is necessary to supply "or" conditions for a parameter, this should be done by supplying multiple queries. + + + + + + AnnotableWhereType is an abstract base type for querying an annotable artefact. + + + + + Annotation is a parameter for matching the details of an annotatable object's annotations. It allows for querying based on the details of an annotation. + + + + + + + + AnnotationWhereType defines the structure for querying the details of an annotation. + + + + + Type is a parameter for matching the type field of an annotation. + + + + + Title is a parameter for matching the title field of an annotation. + + + + + Text is a parameter for matching the text field of an annotation. + + + + + + + + IdentifiableWhereType is an abstract base type that serves as the basis for any query for an identifiable object. + + + + + + + URN is used to match the urn of any SDMX object. + + + + + ID is used to match the id of the identified object. + + + + + + + + + + NameableWhereType is an abstract base type that serves as the basis for any query for a nameable object. + + + + + + + Name is used to match the name of the identified object. It may occur multiple times for its usage within an or-query or for multi-lingual searches, however if multiple values are supplied in an and-query (explicit or implicit), each name search will have to be found in order to constitute a match. The value here can either be an explicit value (exact match) or a regular expression pattern on which to match. + + + + + Description is used to match the description of the identified object. It may occur multiple times for its usage within an or-query or for multi-lingual searches, however if multiple values are supplied in an and-query (explicit or implicit), each description search will have to be found in order to constitute a match. The value here can either be an explicit value (exact match) or a regular expression pattern on which to match. + + + + + + + + + + VersionableQueryType is an abstract base type that serves as the basis for any query for a versionable object. + + + + + + + Version is used to match the version of the versioned object. The version can be specified as either an explicit version number, or a late bound query where the latest version of an object will be returned. + + + + + VersionTo is used to specify a range which the start date of the validity period of version should fall within to create a successful match. + + + + + VersionFrom is used to specify a range which the end date of the validity period of version should fall within to create a successful match. + + + + + VersionActive is used to request object with active or inactive versions, base on the version validity dates. A value of true indicates that only objects where the current date is within the validity period of the version will be matched. + + + + + + + + + + MaintainableQueryType is an abstract base type that serves as the basis for any query for a maintainable object. + + + + + + + AgencyID is used to match the agency id of the maintained object. + + + + + + The type attribute optionally defines the type of object being queried. For queries for distinct types of objects, a fixed value should be specified in the derived queries. For queries that serve to query for like types of objects, this should be required. + + + + + + + + + ItemSchemeQueryType is an abstract base type that serves as the basis for any query for an item scheme. + + + + + + + + + + + + + + + ItemWhere is an abstract substitution head to query for an item within a parent item where or an item scheme query. An item where query is implicitly an and-query - that is the conditions within the item where must all be met in order to return a match. If this is nested within another item where, the meaning is that the conditions specified must be matched within the hierarchy provided. + + + + + + ItemQueryType is an abstract base type that serves as the basis for a query for an item within an item scheme query. A nested item where is provided to query for items nested within other items. The conditions within an item query are implied to be in an and-query. If an id and a child item where condition are supplied, then both conditions will have to met in order for the item query to return true. If, for instance, a query based on names in multiple languages is required, then multiple instances of the element utilizing this type should be used within an or-query container. + + + + + + + Parent is used to query for an item where it declares the item referenced here as its parent. This is used for items that are not nested in a hierarchy. If child items are sought for an item that is contained in a nested hierarchy (e.g. a category) on can query directly for the parent category and request that the child items be returned by specifying cascadeMatchedItems in the detail field of the return details. + + + + + + + + + + + + + StructureWhereType is an abstract base type that serves as the basis for a query for a structure object. + + + + + + + UsedConcept is used to query for a structure that uses the referenced concept as the basis of one of its components. + + + + + UsedRepresentation is used to query for a structure that uses the referenced item scheme for the representation of one of its components. + + + + + + + + + + + + + + + + ComponentListWhere is an abstract substitution head to query for a component list within a structure. A component list where query is implicitly an and-query - that is the conditions within the component list where must all be met in order to return a match. + + + + + + ComponentListWhereType is an abstract base type that serves as the basis for a query for a component list within a structure query. A list of component where children are provided to query for the list's child components. The conditions within a component list query are implied to be in an and-query. If an id and a child component where condition are supplied, then both conditions will have to met in order for the component list query to return true. If, for instance, a query based on names in multiple languages is required, then multiple instances of the element utilizing this type should be used within an or-query container. + + + + + + + + + + + + + ComponentWhere is an abstract substitution head to query for a component within a component list or a structure. A component where query is implicitly an and-query - that is the conditions within the component where must all be met in order to return a match. + + + + + + ComponentWhereType is an abstract base type that serves as the basis for a query for a component within a component list where or a structure query. A concept identity and a local representation condition are available to seek a component that utilizes a particular concept or representation scheme. The conditions within a component query are implied to be in an and-query. If an id and a concept identity condition are supplied, then both conditions will have to met in order for the component query to return true. If, for instance, a query based on names in multiple languages is required, then multiple instances of the element utilizing this type should be used within an or-query container. + + + + + + + ConceptIdentity is used to query for a structure component based on the concept from which it takes its semantic. + + + + + Enumeration is used to query for a structure component based on the item scheme that is used as the enumeration for its representation. This enumeration may be explicit defined by the component (i.e. its local representation), or inherited from the concept from which the component takes its semantic (i.e. the concept core representation). + + + + + + + + + + StructureUsageWhereType is an abstract base type that serves as the basis for a query for a structure usage object. + + + + + + + Structure is used to match the structure referenced by a structure usage object. Only structure usages which reference the supplied structure will be returned. + + + + + + + + + + + + ConceptValueType describes the structure of a query for the value of the underlying concept of a component. It provides a reference to a concept in a concept scheme via a URN and/or a complete set of reference fields, as well as a numeric, text, or un-typed value. + + + + + + + + + + + + + + + CodeValueType is used to query for data or reference metadata where a component which uses the referenced codelist as its representation enumeration has the value provided. Note that this is only applicable when the value is a coded value, which is to say that it does not apply to a codelist which is specified as the representation or an identifiable object target in a metadata target. + + + + + Codelist references the codelist for which the coded value is being sought. + + + + + + The value attribute indicates the coded value that is to be queried for. + + + + + + + + + NumericValue is used to query for a the value of a concept or component based on a numeric search. This is typically used when the value needs to be searched explicitly as a number, such as when data is sought with an observed value greater than some threshold. If only a simple match is required (i.e. the numeric value equals 'x') then the Value element can be used. + + + + + + TextValue is used to query for the value of a concept or component based on textual parameters. The text value can be language specific (where parallel multi-lingual values are available) and is qualified with an operator indicating how the supplied text should be matched against the sought components. If only a simple equality check is necessary, regardless of language, the Value element can be used. + + + + + + TimeValue is used to query for the value of a concept or component based on time parameters. This is typically used when the value needs to be treated explicitly as a time, for example when searching for data after a particular point in time. If only a simple equality check is necessary, the Value element can be used. + + + + + + Value is used to query for the value of a component. This should be used for concepts or components based on a simple value (e.g. a code or a simple string). This should be used when a simple equal/not equal operator is all that is necessary for matching the sought value. + + + + + + SimpleValueType describes the structure of a simple value query. A value is provided as the content in string format. + + + + + + The operator attribute indicates the operator to apply to the string value query. The options are equal and notEqual. + + + + + + + + + NumericValueType describes the structure of a numeric query. A value is provided as the content in decimal format. + + + + + + The operator attribute indicates the operator to apply to the numeric value query, such as equal to or greater than. + + + + + + + + + QueryStringType defines the structure of a string query. + + + + + + The operator attribute indicates how the supplied value should be applied to the objects being searched in order to constitute a match. For example, a value of "EqualTo" means the value of the field being search should exactly match the value supplied. See the defining type for further details. + + + + + + + + + QueryIDType defines the structure of a query for an identifier. + + + + + + The operator attribute indicates how the supplied value should be applied to the objects being searched in order to constitute a match. For example, a value of "EqualTo" means the value of the field being search should exactly match the value supplied. See the defining type for further details. + + + + + + + + + QueryNestedIDType defines the structure of a query for a nested identifier. + + + + + + The operator attribute indicates how the supplied value should be applied to the objects being searched in order to constitute a match. For example, a value of "EqualTo" means the value of the field being search should exactly match the value supplied. See the defining type for further details. + + + + + + + + + QueryTextType describes the structure of a textual query value. A language must be specified if parallel multi-lingual values are available, otherwise it is ignored. + + + + + + The operator attribute indicates how the supplied value should be applied to the objects being searched in order to constitute a match. For example, a value of "EqualTo" means the value of the field being search should exactly match the value supplied. See the defining type for further details. + + + + + + + + + TimePeriodValueType describes the structure of a time period query. A value is provided as the content in the SDMX time period format. + + + + + + The operator attribute indicates the operator to apply to the value query, such as equal to or greater than. + + + + + The reportingYearStartDay attribute allows a reporting year start day to be specified for the reporting period time value. If this time value provided is not a report period, this value can be ignored. If an explicit value is provided, this will effectively turn the time parameter into a distinct time range. For example if the time parameter value is "2010-Q1" and this attribute has a value of "--04-01", the parameter will be treated as "2010-04-01/2010-06-30". If a value of "Any" is provided, then data will be matched regardless of its reporting year start day. For example, a query of 2011-A1 would return all data that belongs to a reporting year of 2011, regardless of the start day of the reporting year. For the puroses of matching data reporting against a Gregorian period against a time parameter value that is a reporting period, a value of "Any" will be treated as a start day of January 1. Therefore, if the time paramter value was 2011-A1, data reported against 2011 would be matched but data reporting against '2011-06/P1Y' would not be matched. + + + + + + + + + ReportingYearStartDayQueryType is a simple type for specifying the reporting year start day in a time query parameter. An explicit value or "Any" can be provided. + + + + + + + AnyQueryType is a single enumeration of the value "Any" which is meant to be used in union with other simple types when a query allows for any of the possible values. + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryCategorisation.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryCategorisation.xsd new file mode 100644 index 0000000..6d561cf --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryCategorisation.xsd @@ -0,0 +1,87 @@ + + + + + + + + SDMX Categorisation Query Module + The categorisation query module provides the construct of a query for a categorisation. + + + + + CategorisationQueryType defines the structure of a categorisation query. The parameters for the query are contained in the CategorisationWhere element. The References element is used to indicate how objects that are referenced from the matched categorisations should be returned. + + + + + + + + + + + + + + CategorisationWhere defines the parameters for a categorisation query. All parameters must be matched for an object to satisfy the query.In addition to querying based on the basic maintainable properties, it is also possible to search based on the source object being categorized and target category the object is categorized against. + + + + + + CategorisationWhereBaseType is an abstract base type which forms the basis for the CategorisationWhereType. + + + + + + + + + + + + + + + + + + + + + + + CategorisationWhereType contains a set of parameters for a categorisation query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + CategoryScheme references a category scheme for which categorisations or sought for any of the scheme's categories. Any categorisation which has a target of a category defined in the scheme will be returned. + + + + + TargetCategory references the category that defines the target of the categorisation (the category which an object is categorized against). Only categorisations which refence the category supplied here will be returned. + + + + + ObjectReference references the object that is the source of the categorisation (the object which is categorized). Only categorisations which reference the object supplied here will be returned. + + + + + CategorisedObjectType is used to specify the type of objects that are categorised by the categorisations being sought. For example, this could be used to find an caategorisation which classifies a code list. + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryCategory.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryCategory.xsd new file mode 100644 index 0000000..6a960de --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryCategory.xsd @@ -0,0 +1,85 @@ + + + + + + + + SDMX Category Query Module + The category query module provides the construct of a query for a category scheme. + + + + + CategorySchemeQueryType defines the structure of a category scheme query. The parameters for the query are contained in the CategorySchemeWhere element. The References element is used to indicate how objects that reference the matched category scheme should be returned. + + + + + + + + + + + + + + CategorySchemeWhere contains the parameters for a category scheme query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to search for a category scheme based on the details of its categories. In any case, the category scheme will be returned according the indicated return detail. + + + + + + CategorySchemeWhereType defines the parameters of a category scheme query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + + + + + + + + + + + CategoryWhere is used to query for categories matching the parameters supplied. It allows for nested category queries so that hierarchical categories can be queried explicitly by their nested level, although a top level category will always result in a search for categories at any level. This is an implicit set of "and" parameters, meaning all of the conditions must be met in order to return a match. + + + + + + CategoryQueryWhereType contains a set of parameters for matching a category. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryCodelist.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryCodelist.xsd new file mode 100644 index 0000000..98b2600 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryCodelist.xsd @@ -0,0 +1,84 @@ + + + + + + + + SDMX Code List Query Module + The code list query module provides the construct of a query for a code list. + + + + + CodelistQueryType defines the structure of a codelist query. The parameters for the query are contained in the CodelistWhere element. The References element is used to indicate how objects that reference the matched codelist should be returned. + + + + + + + + + + + + + + CodelistWhere defines the parameters for a codelist query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to search for a codlist based on the details of its codes. In any case, the codelist will be returned according the indicated return detail. + + + + + + CodelistWhereType contains the parameters of a codelist query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + + + + + + + + + + + CodeWhere is used to query for codes matching the parameters supplied. This is an implicit set of "and" parameters, meaning all of the conditions must be met in order to return a match. + + + + + + CodeWhereType defines a set of parameters for matching a code. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryConcept.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryConcept.xsd new file mode 100644 index 0000000..d9c779b --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryConcept.xsd @@ -0,0 +1,100 @@ + + + + + + + + SDMX Concept Query Module + The concept query module provides the construct of a query for a concept schemes. + + + + + ConceptSchemeQueryType defines the structure of a category scheme query. The parameters for the query are contained in the ConceptSchemeWhere element. The References element is used to indicate how objects that reference or are referenced from the matched concept scheme should be returned. + + + + + + + + + + + + + + ConceptSchemeWhere defines the parameters for a concept scheme query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to search for a concept scheme based on the details of its concepts. In any case, the concept scheme will be returned according the indicated return detail. + + + + + + ConceptSchemeWhereType contains the parameters of a concept scheme query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + + + + + + + + + + + ConceptWhere is used to query for concepts matching the parameters supplied. This is an implicit set of "and" parameters, meaning all of the conditions must be met in order to return a match. + + + + + + ConceptWhereBaseType is an abstract base type that forms the basis for the ConceptWhereType. + + + + + + + + + + + + + + + + + + + ConceptWhereType defines a set of parameters for matching a concept. All supplied parameters must be matched in order for an object to satisfy the query. In addition to the base parameters for an item, a concept can be queried based on the item scheme that is used as a core representation. + + + + + + + Enumeration is used to query for a concept based on the codelist that is used as the enumeration for its core representation. + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryConstraint.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryConstraint.xsd new file mode 100644 index 0000000..fd59c71 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryConstraint.xsd @@ -0,0 +1,145 @@ + + + + + + + + SDMX Constraint Query Module + The constraint query module provides the construct of a query for an attachment or content constraint. + + + + + ConstraintQueryType defines the structure of a constraint query. The parameters for the query are contained in the ConstraintWhere element. The References element is used to indicate how objects that are referenced from the matched constraint should be returned. + + + + + + + + + + + + + + AttachmentConstraintWhere contains the parameters for a constraint query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to search for a constraint based on the objects it applies to. + + + + + + ConstraintWhereBaseType is an abstract base type which forms the basis for the ConstraintWhereType. + + + + + + + + + + + + + + + + + + The type attribute indicates the type of constraint that is being queried for, with a default of Any, meaning both content and attachment constraints will be searched. + + + + + + + + + ConstraintWhereType contains the parameters of a constraint query. All supplied parameters must be matched in order for an object to stratify the query. + + + + + + + ConstraintAttachmentWhere identifies a collection of objects to which a constraint may be attached. This container is an implicit and-query, meaning all of the objects referenced in here must be part of the constraint attachment in order for a constraint to match. + + + + + + The allowable attribute indicates whether the returned search should be limited to only allowable constraints. This only applies to content constraint. If this attribute has a value of true, this indicates that only matching allowable content constraints should be returned. If this is false, than only actual content constraints returned. If no value is provided, all matching content constraints will be returned, regardless of whether they are stating actual or allowable content. + + + + + + + + + ConstraintAttachmentWhereType describes the structure for querying for a constraint based on the objects it is attached to. A constraint attachment query is implicitly an and-query meaning all of the referenced objects must be part of a constraints attachment in order to return a match. It is treated as a condition within its parent query. + + + + + DataProviderReference references a data provider to which a constraint is attached. It is referenced via a URN and/or a full set of reference fields. If a constraint is attached to the data provider referenced, a match will be returned. + + + + + DataflowReference references a data flow to which a constraint is attached. It is referenced via a URN and/or a full set of reference fields. If a constraint is attached to the data flow referenced, a match will be returned. + + + + + DataStructureReference references a data structure definition to which a constraint is attached. It is referenced via a URN and/or a full set of reference fields. If a constraint is attached to the data structure definition referenced, a match will be returned. + + + + + MetadataflowReference references a metadata flow to which a constraint is attached. It is referenced via a URN and/or a full set of reference fields. If a constraint is attached to the metadata flow referenced, a match will be returned. + + + + + MetadataStructureReference references a metadata structure definition to which a constraint is attached. It is referenced via a URN and/or a full set of reference fields. If a constraint is attached to the metadata structure definition referenced, a match will be returned. + + + + + ProvisionAgreementReference references a provision agreement to which a constraint is attached. It is referenced via a URN and/or a full set of reference fields. If a constraint is attached to the provision agreement referenced, a match will be returned. + + + + + DataSetReference references a data set to which a constraint is attached. If a constraint is attached to the data set referenced, a match will be returned. + + + + + MetadataSetReference references a reference metadata set to which a constraint is attached. If a constraint is attached to the metadata set referenced, a match will be returned. + + + + + DataSourceURL references a queryable data source to which a constraint it attached. The data source is referenced by its data URL. If a constraint is attached to the data source described (by matching the data URL), a match will be returned. + + + + + + + + ConstraintTypeCodelistType defines a list of types for a constraint for the purpose of querying. + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryData.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryData.xsd new file mode 100644 index 0000000..ddbd76b --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryData.xsd @@ -0,0 +1,463 @@ + + + + + + + + SDMX Data Query Module + The data query module provides the construct of a query for a data. + + + + + DataQueryType defines the structure of a query for data. This is generally appliable for any data request, but can be refined depending on the type of data being queried (generic or structured, time series specific or not) to the requirements of the requested format. + + + + + ReturnDetails contains the details of how the returned data should be structured, what type of data (e.g. active or deleted observations), and the limit of the amount of observations to be returned. + + + + + DataWhere contains the details of the data query. + + + + + + + + TimeSeriesDataQueryType defines the structure of a query for data. This specifically applies to requesting time series only structured data. + + + + + + + + + + + + + + GenericDataQueryType defines the structure of a query for data formatted in the generic format. This structure generally applies to any type of generic data request, but can be refined to request time series only data. + + + + + + + + + + + + + + GenericTimeSeriesDataQueryType defines the structure of a query for time series only data formatted in the generic format. + + + + + + + + + + + + + + DataReturnDetailsBaseType is an abstract base type which forms the basis of the DataReturnDetailsType. + + + + + + The detail attribute is used to indicate whether the response to the query should return the full details of matched data sets, or just a subset of the information should be returned. A value of "Full" indicates that the complete data set (including data and documentation) will be returned. A value of "DataOnly" indicates that only the observation values and keys should be returned. A value of "SeriesKeyOnly" indicates that only the Series elements and their keys (i.e. Dimension values) should be returned. A value of "NoData" indicates that only documentation should be returned (i.e. the DataSet, Group, and Series level Attributes). + + + + + + + + + DataReturnDetailsType specifies the specifics of the how data should be returned, including how it should be structured and how many and what type (e.g. active or deleted) observations should be returned. + + + + + + + FirstNObservations specifies that number of observations indicated should be returned, starting from the earliest observation. Note that this can be used in conjunction with the LastNObservations. For example, if both FirstNObservations and LastNObservations had a value of 1, then the first and the last observation would be returned. + + + + + LastNObservations specifies that number of observations indicated should be returned, starting from the latest observation and working back. Note that this can be used in conjunction with the FirstNObservations. For example, if both FirstNObservations and LastNObservations had a value of 1, then the first and the last observation would be returned. + + + + + Structure defines how the is requested to be oriented in the returned message. For each data structure, dataflow, or provision agreement, a dimension at the observation level can be specified, and in the case that the dimension is a measure and the query is for structured data, the measure can be specified as being explicit. For any matched data in which there is not a structure specification, the query service can orient that data in any manner, although it is recommended that time be used as the observation dimension. + + + + + + The observationAction attribute specifies the type of observations (added, deleted, udpated, or current) to be returned. In the absence of the Updated parameter, this will return all observations that have ever existed for Added, any observations that have ever been updated for Updated, and any observations that have ever been deleted for Deleted. Note that since observations themselves contain no status in the data messages, it is only possible to query for active observations or deleted observations, but not both. It is possible to subset active observation into recently added and recently updated, however it is only possible to retrieve on or the other. If active observations are returned, there will be no distinction as to whether an individual observation was updated or added during the requested Update parameter. + + + + + + + + + DataReturnDetailType contains a set of enumerations that indicate how much detail should be returned for a data set. + + + + + The entire data set (including all data, documentation, and annotations) will be returned. + + + + + Only the observed values and their keys will be returned. Annotations and documentation (i.e. Attributes) and therefore Groups, will be excluded. + + + + + Only the series elements and the values for the dimensions will be returned. Annotations, documentation, and observations will be excluded. + + + + + Returns all documentation at the DataSet, Group, and Series level without any Observations (therefore, Observation level documentation is not returned). Annotations are not returned. + + + + + + + + GenericDataReturnDetailsType specifies the specifics of the how data should be returned as it pertains to a request for generic data. + + + + + + + + + + + + + + + + GenericTimeSeriesDataReturnDetailsType specifies the specifics of the how data should be returned as it pertains to a request for time series only oriented data in the generic format. + + + + + + + + + + + + + + + + TimeSeriesDataReturnDetailsType specifies the specifics of the how data should be returned as it pertains to a request for time series only oriented data in the structured format. + + + + + + + + + + + + + + + + DataParametersType defines the parameters for querying for data. This structure is refined by separate And/Or constructs which make logical restrictions on which parameters apply in such cases. + + + + + DataSetID is used to match the id of the data set. Only data from data sets with an identifier satisfying these conditions will be matched. + + + + + DataProvider is used to match the provider of data to the referenced data provider. Only data from data sets provided by the referenced data provider will be matched. + + + + + DataStructure is used to match the underlying structure of the data. Only data from data sets that conform to referenced data structure definition will be matched. + + + + + Dataflow is used to match the flow which data is reported against. Only data from data sets report against referenced dataflow will be matched. + + + + + ProvisionAgreement is used to match the provision agreement which data is reported against. Only data from data sets report against the referenced provision agreement will be matched. + + + + + Category is used to match a data based on the categorization of its underlying structure (data structure definition), or the usage of that structure (data flow). Only data whose underlying structure or structure usage are categorized against the referenced category will be matched. + + + + + Updated is used to match data based on when it was last updated (including additions and deletions). Only data which satisfies the conditions for the last update parameters supplied here will be matched. + + + + + ConceptValue is used to match data based on the value of a particular concept. This concept may be used as a dimension, attribute, or measure for the data. So long as the referenced concept has the specified value for a given data point, it will be matched. + + + + + RepresentationValue is used to match data based on a representation scheme having a particular value. This representation scheme may be used as the representation of a dimension, attribute, or measure. So long as the value of the concept using the referenced codelist has the value specified, any data point for the concept will be matched. + + + + + DimensionValue is used to match data based on the value of a dimension. Any data with the dimension with the supplied identifier satisfies the conditions supplied will be matched. + + + + + TimeDimensionValue is used to match data based on the value of the time dimension. Any data with a time value satisfying the conditions supplied will be matched. + + + + + AttributeValue is used to match data based on the value of an attribute. Any data with an attribute with the supplied identifier satisfies the conditions supplied will be matched. + + + + + PrimaryMeasureValue is used to match data based on the value of the primary measure. Any data with its value satisfying the conditions supplied will be matched. + + + + + AttachmentConstraint references an attachment constraint in order to match data which matches the effective data keys or cube regions defined in the constraint. Data will be returned by first matching data on the keys and cube regions that are marked as included (or all data if none), and then excluding the data that satisfies the conditions of the excluded keys and cube regions. + + + + + TimeFormat is used to match data when a frequency dimension is not explicitly defined. Only data reported against the supplied time data type will be returned. + + + + + Or contains a collection of additional parameters, any one of which can be satisfied to result in a match. + + + + + And contains a collection of additional parameters, all of which must be satisfied to result in a match. + + + + + + + + DataParametersOrType refines the base data parameters to define a set of parameters joined by an "or" condition. Only one of the parameters supplied in an instance of this type can be satisfied to result in a match. + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataParametersAndType refines the base data parameters to define a set of parameters joined by an "and" conditions. All of the parameters supplied in an instance of this type must be satisfied to result in a match. As a result of this condition, the maximum occurrence of some parameters has been reduced so as to not allow for impossible conditions to be specified (for example data cannot be matched is it is specified that the data set identifier should be "xyz" and the data identifier should be "abc". + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataStructureComponentValueQueryType is an abstract base type that is the basis for query a data structure definition component for a particular value. Multiple values may be supplied, but the component value must match all of the value conditions supplied in order to return a match. + + + + + ID provides the identifier for component for which the value is sought. + + + + + + + + + + + + + + DimensionValueType is used to query for data where a given dimension has a particular value. + + + + + + + + + + + + + + + + + + AttributeValueType is used to query for data where a given attribute has a particular value. + + + + + + + + + + + + + + + + + + + PrimaryMeasureValueType is used to query for data where the primary measure (i.e. the observed value) has a particular value. + + + + + + + + + + + + + + + + + + + TimeDimensionValueType is used to query for data where the time dimension has a particular value. + + + + + + + + + + + + + + + + ObservationActionCodeType enumerates the type of observations to be returned. + + + + + Active observations, regardless of when they were added or updated will be returned. + + + + + Only newly added observations will be returned. + + + + + Only updated observations will be returned. + + + + + Only deleted observations will be returned. + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryDataStructure.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryDataStructure.xsd new file mode 100644 index 0000000..15d652e --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryDataStructure.xsd @@ -0,0 +1,265 @@ + + + + + + + + SDMX Data Structure Query Module + The data structure query module provides the construct of a query for a data structure definition. + + + + + DataStructureQueryType defines the structure of a data structure definition query. The parameters for the query are contained in the DataStructureWhere element. The References element is used to indicate how objects that reference or are referenced from the matched data structure definition should be returned. + + + + + + + + + + + + + + DataStructureWhere contains the parameters for a data structure definition query. All parameters must be matched for an object to satisfy the query. The query is simply a refinement of the base structure query to make the parameters specific to the data structure definition. + + + + + + DataStructureWhereBaseType is an abstract base type that forms the basis of the DataStructureWhereType. + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataStructureWhereType defines the parameters of a data structure definition query. In addition to querying based on the identification, it is also possible to search for data structure definitions based on information about its components. + + + + + + + + + + + + + + + + + GroupWhere is used to query for a data structure definition that contains a group meeting the conditions detailed in this container. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + GroupWhereBaseType is an abstract base type that forms the basis for the GroupWhereType. + + + + + + + + + + + + + + + + + GroupWhereType defines the parameters querying for a data structure definition based a group meeting the conditions detailed. Parameters include identification, dimensions used in the group, and the group's referenced attachment constraint. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + + AttachmentConstraint queries for a group where the referenced attachment constraint defines the contents of the group. + + + + + + + + + + GroupDimensionWhere is used to query a group based on the details of the dimensions it groups. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + DataStructureComponentWhereType defines the basic information for querying for a data structure definition component. The component can be queried based on its identification, the concept from which it takes its semantic, and the code list it uses as its representation,. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + + + + + + + + + + + AttributeWhere is used to query for a data structure definition that contains an attribute meeting the conditions contained in this structure. The attribute can be queried based on its identification, the concept from which it takes its semantic, its attachment level, the role it plays, and the code list it uses as the enumeration of its representation. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + DimensionWhere is used to query for a data structure definition that contains a dimension meeting the conditions contained in this structure. The dimension can be queried based on its identification, the concept from which it takes its semantic, the role it plays, and the code list it uses as the enumeration of its representation. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + TimeDimensionWhere is used to query for a data structure definition that contains a time dimension meeting the conditions contained in this structure. The time dimension can be queried based on its identification and the concept from which it takes its semantic. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + PrimaryMeasureWhere is used to query for a data structure definition that contains a primary measure meeting the conditions contained in this structure. The primary measure can be queried based on its identification, the concept from which it takes its semantic, and the code list it uses as the enumeration of its representation. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + MeasureDimensionWhere is used to query for a data structure definition that contains a measure dimension meeting the conditions contained in this structure. The cross-sectional measure can be queried based on its identification, the concept from which it takes its semantic, and the concept scheme it uses as the enumeration of its representation. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + AttributeWhereType describes the structure of an attribute query. An attribute can be queried based on its identification, the concept from which it takes its semantic, the role it plays, and the code list it uses as the enumeration of its representation. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + + Role is used to specify the role of the attribute. + + + + + + + + + + DimensionWhereType describes the structure of a dimension query. A dimension can be queried based on its identification, the concept from which it takes its semantic, the role it plays, and the code list it uses as the enumeration of its representation. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + + Role is used to specify the role of the dimension. + + + + + + + + + + TimeDimensionWhereType describes the structure of a time dimension query. The time dimension can be queried based on the concept from which it takes its semantic. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + + + + + + + + + MeasureDimensionWhereBaseType is an abstract base type which forms the basis for a measure dimension query. + + + + + + + + + + + + + + + + MeasureDimensionWhereType describes the structure of a measure dimension query. A measure dimension can be queried based on its identification, the concept from which it takes its semantic, the role it plays, and the concept scheme which defines its measure concepts. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + + Role is used to specify the role of the dimension. + + + + + + + + + + MeasureWhereType describes the structure of a measure query. The primary measure can be queried based on the concept from which it takes its semantic, and the code list it uses as the enumeration of its representation. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryDataflow.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryDataflow.xsd new file mode 100644 index 0000000..fe7ba34 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryDataflow.xsd @@ -0,0 +1,60 @@ + + + + + + + + SDMX Data Flow Query Module + The data flow query module provides the construct of a query for a data flow. + + + + + DataflowQueryType defines the structure of a dataflow query. The parameters for the query are contained in the DataflowWhere element. The References element is used to indicate how objects that reference or are referenced from the matched dataflow should be returned. + + + + + + + + + + + + + + DataflowWhere defines the parameters for a dataflow query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to search for a dataflow based on the key family it defines the usage of. + + + + + + DataflowWhereType contains the parameters of a dataflow query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + + Structure is used to indicate which key family the dataflow must define a usage for in order to constitute a match. + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryHierarchicalCodelist.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryHierarchicalCodelist.xsd new file mode 100644 index 0000000..d6fcf3f --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryHierarchicalCodelist.xsd @@ -0,0 +1,76 @@ + + + + + + + + SDMX Hierarchical Code List Query Module + The hierarchical code list query module provides the construct of a query for a hierarchical code list. + + + + + HierarchicalCodelistQueryType defines the structure of a hierarchical codelist query. The parameters for the query are contained in the HierarchicalCodelistWhere element. The References element is used to indicate how objects that are referenced from the matched hierarchical codelist should be returned. + + + + + + + + + + + + + + HierarchicalCodelistWhere defines the parameters for a hierarchical codelist query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to search for a hierarchical codelist based on the codelists it arranges into hierarchies. + + + + + + HierarchicalCodelistWhereBaseType is an abstract base type which forms the basis for the HierarchicalCodelistWhereType. + + + + + + + + + + + + + + + + + + The type attribute indicates the type of constraint that is being queried for, with a default of Any, meaning both content and attachment constraints will be searched. + + + + + + + + + HierarchicalCodelistWhereType contains the parameters of a hierarchical codelist query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + IncludedCodelist is used to reference a codelist which the hierarchical codelist to be matched references. + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryMetadata.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryMetadata.xsd new file mode 100644 index 0000000..0911503 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryMetadata.xsd @@ -0,0 +1,274 @@ + + + + + + + + SDMX Metadata Query Module + The metadata query module provides the construct of a query for metadata. + + + + + MetadataQueryType defines the structure of a reference metadata query. Reference metadata is queried as individual reports. The result of this query will be a collection of metadata sets, with only the relevant metadata reports contained within them. If no report level parameters are specified, then the query will result in entire metadata sets being returned. + + + + + ReturnDetails specifies the details of how the reference metadata should be returned. + + + + + MetadataParameters contains the parameters that are to be matched in order to determine which metadata reports are to be returned as the result of the query. + + + + + + + + MetadataReturnDetailsType is a structure for detailing how reference metadata should be returned. Only a default size limit can be specified. + + + + + + + + + MetadataParametersType defines the parameters for querying for reference metadata. This structure is refined by separate And/Or constructs which make logical restrictions on which parameters apply in such cases. + + + + + MetadataSetID is used to match the id of the metadata set. Only metadata reports from data sets with an identifier satisfying these conditions will be matched. + + + + + DataProviderReference is used to match the provider of reference metadata to the referenced data provider. Only metadata reports from metadata sets provided by the referenced data provider will be matched. + + + + + MetadataStructureReference is used to match the underlying structure of the data. Only metadata reports from metadata sets that conform to referenced metadata structure definition will be matched. + + + + + MetadataflowReference is used to match the flow which reference metadata is reported against. Only metadata reports from metadata sets report against referenced metadata flow will be matched. + + + + + ProvisionAgreement is used to match the provision agreement which metadata is reported against. Only metadata from metadata sets report against the referenced provision agreement will be matched. + + + + + CategoryReference is used to match a reference metadata based on the categorization of its underlying structure (metadata structure definition), or the usage of that structure (metadata flow). Only metadata reports whose underlying structure or structure usage are categorized against the referenced category will be matched. + + + + + Updated is used to match reference metadata based on when it was last updated. Only metadata reports which satisfy the conditions for the last update parameters supplied here will be matched. + + + + + ConceptValue is used to match reference metadata based on the value of a particular concept which defines a metadata attribute. So long as the referenced concept has the specified value for a metadata attribute anywhere within the report structure, the metadata report which contains that attribute will be matched. + + + + + RepresentationValue is used to match reference metadata based on a codelist having a particular value. This codelist only applies in the context of the representation of a metadata attribute. So long as the value of any metadata attribute within the report structure which uses the referenced codelist has the value specified, any metadata report containing the attribute will be matched. + + + + + MetadataTargetValue is used to match reference metadata based on the target object values of a particular metadata target. If not report structure is specified in the query, this will result in a search across all metadata reports which may use this metadata target. If a value is not given for a target object which is part of this metadata target, it is assumed that all values are allowed for that target object. Thus, if no target object values are given in the entire metadata target, the query will simply match ant report where the reference metadata target is used. All target object value conditions must be met to constitute a match. + + + + + ReportStructureValue is used to match particular reference metadata reports. Only metadata reports based on the referenced report structure will be matched. It is also possible to detail the values of the metadata attributes contained within the reference report. In this case, only metadata reports based on the referenced report structure which have the metadata attribute values specified will be matched. + + + + + AttachmentConstraint references an attachment constraint in order to match reference metadata which matches the effective metadata keys or metadata target regions defined in the constraint. Metadata will be returned by first matching metadata on the keys and metadata target regions that are marked as included (or all metadata if none), and then excluding the metadata that satisfies the conditions of the excluded keys and metadata target regions. + + + + + AttachedObject is used to match reference metadata based on an object which it is attached to, regardless of the report structure or metadata target in which the object is referenced. Any metadata reports attached to the referenced objects will be matched. + + + + + AttachedDataKey is used to match reference metadata based on a data key it is attached to, regardless of the report structure or metadata target in which the data key is referenced. Any metadata reports attached to the supplied data key will be matched. + + + + + AttachedDataSet is used to query for reference metadata based on a data set it is attached to, regardless of the report structure or metadata target in which the data set is referenced. Any metadata reports attached to the supplied metadata key will be matched. + + + + + AttachedReportingPeriod is used to query for reference metadata based on the reporting period to which it is attached, regardless of the report structure or metadata target in which the reference period is referenced. Any metadata reports attached to a reporting period which falls within the range specified will be matched. + + + + + Or contains a collection of additional parameters, any one of which can be satisfied to result in a match. + + + + + And contains a collection of additional parameters, all of which must be satisfied to result in a match. + + + + + + + + MetadataParametersOrType refines the base data parameters to define a set of parameters joined by an "or" condition. Only one of the parameters supplied in an instance of this type can be satisfied to result in a match. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MetadataParametersAndType refines the base data parameters to define a set of parameters joined by an "and" conditions. All of the parameters supplied in an instance of this type must be satisfied to result in a match. As a result of this condition, the maximum occurrence of some parameters has been reduced so as to not allow for impossible conditions to be specified (for example data cannot be matched is it is specified that the data set identifier should be "xyz" and the data identifier should be "abc". + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MetadataTargetValueType describes the structure that is used to match reference metadata where a given metadata target's target object have particular values. If a value is not given for a target object which is part of the metadata target, it is assumed that all values are allowed for that target object. Thus, if no target object values are given in the entire metadata target, the query will simply match ant report where the reference metadata target is used. All target object value conditions must be met to constitute a match. + + + + + + TargetObjectValue is used to match reference metadata where a given target object in a metadata target references a particular object or time period. + + + + + + + + IdentifierComponentValueType describes the structure that is used to match reference metadata where a given identifier component has a particular value. + + + + + ID identifies the metadata target object. + + + + + + DataSet provides a reference to a data set which the target object should reference to result in a match. + + + + + DataKey provides a data key (set of dimension values) which the target object should reference to result in a match. + + + + + Object provides a reference to any SDMX identifiable object which the target object should reference to result in a match. + + + + + TimeValue is used to provide a time value or range for matching a reporting period which the target object should reference to result in a match. + + + + + + + + + ReportStructureValueType describes the structure that is used to match reference metadata where the metadata attributes of a report structure have particular values. All metadata attribute value conditions must be met to constitute a match. + + + + + + MetadataAttributeValue is used to match reference metadata where a metadata attribute has a particular value within the referenced report structure. + + + + + + + + MetadataAttributeValueType describes the structure that is used to match reference metadata where a metadata attribute has a particular value. Metadata attribute value queries can be nested for querying nested metadata attributes. If no value is provided, then simply the presence of the metadata attribute within the given context will result in a match. All nested metadata attribute value conditions must be met to constitute a match. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryMetadataStructure.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryMetadataStructure.xsd new file mode 100644 index 0000000..c3fd892 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryMetadataStructure.xsd @@ -0,0 +1,196 @@ + + + + + + + + SDMX Metadata Structure Definition Query Module + The metadata structure definition query module provides the construct of a query for a metadata structure definition. + + + + + MetadataStructureQueryType defines the structure of a metadata structure definition query. The parameters for the query are contained in the MetadataStructureDefinitionWhere element. The References element is used to indicate how objects that reference or are referenced from the matched metadata structure definition should be returned. + + + + + + + + + + + + + + MetadataStructureWhere contains the parameters for a metadata structure definition query. All parameters must be matched for an object to satisfy the query. The query is simply a refinement of the base structure query to make the parameters specific to the metadata structure definition. + + + + + + MetadataStructureWhereBaseType is an abstract base type the forms the basis for the MetadataStructureWhereType. + + + + + + + + + + + + + + + + + + + + + + + + + MetadataStructureWhereType defines the parameters of a metadata structure definition query. In addition to querying based on the identification, it is also possible to search for metadata structure definitions based on information about its components. + + + + + + + + + + + + + + + + MetadataTargetWhere is used to query for a metadata structure definition that contains a metadata target meeting the conditions contained in this structure. The metadata target can be queried based on its identification and/or the details of its target objects. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + MetadataTargetWhereType describes the structure that is used to query for metadata structure definitions containing a metadata target meeting the conditions detailed. Conditions include the identification and the details of the target objects which make up the metadata target. + + + + + + + + + + + + + + + + + + + IdentifierComponentWhere is used to query for specific target identifiers or metadata structure definitions where a contained identifier component meets the conditions detailed. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + TargetObjectWhereBaseType is an abstract base type that forms the basis for the TargetObjectWhereType. + + + + + + + + + + + + + + + TargetObjectWhereType describes the structure of a target object query. A target object can be queried based on its identification, its type (i.e. data set target, key descriptor values target, report period target, or identifiable object target), and in the case of an identifiable object target, an item scheme which enumerates the possible values and/or the class of the target object reference. + + + + + + The type attribute is used to query for a target object of a given type (i.e. data set target, key descriptor values target, report period target, or identifiable object target) + + + + + The targetClass attribute is used to query for an identifiable object target based on the class its target object. + + + + + + + + + ReportStructureWhere is used to query for metadata structure definitions where a given report structure meets the conditions specified. A report structure can be queried based on identification or details about its metadata attributes. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + ReportStructureWhereType defines the parameters for matching based on the details of a report structure. This is used to query for metadata structure definitions where a given report structure meets the conditions specified. A report structure can be queried based on identification and details about its metadata attributes. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + + + + + + + + + + + + MetadataAttributeWhere is a parameter which is used in a report structure parameter or to query metadata structure definitions where a contained metadata attribute meets the conditions specified. A metadata attribute can be queried based on its identification, the concept from which it takes its semantic, and an item scheme it uses as its representation. Nested metadata attributes allow for the querying of metadata attributes explicitly at nested level, although a top level metadata attribute query will be processed by querying metadata attributes at any level. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + MetadataAttributeWhereBaseType is an abstract base type that forms the basis for the MetadataAttributeWhereType. + + + + + + + + + + + + + + + MetadataAttributeWhereType describes the parameters for a metadata attribute. A metadata attribute can be queried based on its identification, the concept from which it takes its semantic, and an item scheme it uses as its representation. Nested metadata attributes allow for the querying of metadata attributes explicitly at nested level, although a top level metadata attribute query will be processed by querying metadata attributes at any level. This is an implicit set of "and" parameters, that is the conditions within this must all be met in order to return a match. + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryMetadataflow.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryMetadataflow.xsd new file mode 100644 index 0000000..5817aa0 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryMetadataflow.xsd @@ -0,0 +1,60 @@ + + + + + + + + SDMX Metadata Flow Query Module + The metadata flow query module provides the construct of a query for a metadata flow. + + + + + MetadataflowQueryType defines the structure of a metadataflow query. The parameters for the query are contained in the MetadataflowWhere element. The References element is used to indicate how objects that reference or are referenced from the matched metadataflow should be returned. + + + + + + + + + + + + + + MetadataflowWhere contains the parameters for a metadataflow query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to search for a metadataflow based on the metadata structure definition it defines the usage of. + + + + + + MetadataflowWhereType contains the parameters of a metadataflow query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + + MetadataStructureReference is used to indicate which metadata structure definition the metadataflow must define a usage for in order to constitute a match. + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryOrganisation.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryOrganisation.xsd new file mode 100644 index 0000000..8d2ae73 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryOrganisation.xsd @@ -0,0 +1,104 @@ + + + + + + + + SDMX Organisation Query Module + The organisation query module provides the construct of a query for any type of organisation scheme. + + + + + OrganisationSchemeQueryType defines the structure of an organisation scheme query. The parameters for the query are contained in the OrganisationSchemeWhere element. The References element is used to indicate how objects that reference the matched organisation scheme should be returned. + + + + + + + + + + + + + + OrganisationSchemeWhere defines the parameters for an organisation scheme query, regardless of the specific type of organisation scheme being sought. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to search for an organisation scheme based on the details of its organisations. In any case, the organisation scheme will be returned according the indicated return detail. + + + + + + OrganisationSchemeWhereType contains the parameters of an organisation scheme query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + + + + + + The type attribute indicates the type of organisation scheme which is being queried for, with the default being any organisation scheme. Note that agency, data consumer, and data provider scheme all have fixed identifiers and versions, so specifying these types with parameters for the identifier and/or version which do not match these fixed values will never return a result. + + + + + + + + + OrganisationWhere is used to query for organisations matching the parameters supplied. This is an implicit set of "and" parameters, meaning all of the conditions must be met in order to return a match. + + + + + + OrganisationWhereType defines a set of parameters for matching an organisation. In addition to the base parameters for any item, there is an additional parameter for matching an organisation based on the roles it serves. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + Parent is only applicable when searching for organisation units, and is used to match organisations which have a parent organisation unit which is referenced here. + + + + + + + + + + + OrganisationSchemeTypeCodeType enumerates the possible types of organisation schemes that can be queried for. + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryProcess.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryProcess.xsd new file mode 100644 index 0000000..76bee5a --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryProcess.xsd @@ -0,0 +1,135 @@ + + + + + + + + SDMX Process Query Module + The process query module provides the construct of a query for a process. + + + + + ProcessQueryType defines the structure of a process query. The parameters for the query are contained in the ProcessWhere element. The References element is used to indicate how objects that are referenced from the matched process scheme should be returned. + + + + + + + + + + + + + + ProcessWhere contains the parameters for a process query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to query based on the details of the process steps defined within the process. In any case, the entire process will be returned according the indicated return detail. + + + + + + ProcessWhereBaseType is an abstract base type which forms the basis for the ProcessWhereType. + + + + + + + + + + + + + + + + + + + + + + + ProcessWhereType defines the parameters of a process query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + ProcessStepWhere is used to query for process steps matching the parameters supplied. It allows for nested process step queries so that hierarchical steps can be queried explicitly by their nested level, although a top level step will always result in a search for process steps at any level. This is an implicit set of "and" parameters, meaning all of the conditions must be met in order to return a match. + + + + + + + + + + ProcessStepWhereType defines a set of parameters for matching a category. All supplied parameters must be matched in order for an object to satisfy the query. In addition to the base item parameters, there are also parameters for matching based on the objects which serve as the input or output to the process step. + + + + + + + InputOrOutputObject is a parameter for matching a process step based on the referenced object, and whether it is an input or an output to the step. + + + + + ProcessStepWhere is used to query for process steps within a the particular process step. This is an implicit set of "and" parameters, meaning all of the conditions must be met in order to return a match. + + + + + + + + + + InputOrOutputObjectType describes the structure of input or output condition for a process step query. It contains reference to an object, as will as an attribute indicates whether the object should be an input, output, or either of the two to the step. + + + + + ObjectReference is used to query for a process containing process steps where the referenced object is input or output to the process step. + + + + + + The type attribute is used to indicate whether the referenced object should be an input, output, or either of the two to the process step. The default for this is Any. + + + + + + + InputOutputTypeCodeType enumerates the role an object plays in a process step. + + + + + Input - referenced object is an input to the process step. + + + + + Output - referenced object is an output to the process step. + + + + + Any - referenced object is either an input or an output to the process step. + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryProvisionAgreement.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryProvisionAgreement.xsd new file mode 100644 index 0000000..0d1ce44 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryProvisionAgreement.xsd @@ -0,0 +1,81 @@ + + + + + + + + SDMX Provision Agreement Query Module + The provision agreement query module provides the construct of a query for a provision agreement. + + + + + ProvisionAgreementQueryType defines the structure of a provision agreement query. The parameters for the query are contained in the ProvisionAgreementWhere element. The References element is used to indicate how objects that reference or are referenced from the matched provision agreement should be returned. + + + + + + + + + + + + + + ProvisionAgreementWhere contains the parameters for a provision agreement query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to search for a provision agreement based on the data provider and the structure usage it pairs. + + + + + + ProvisionAgreementWhereBaseType is an abstract base type which forms the basis for the ProvisionAgreementWhereType. + + + + + + + + + + + + + + + + + + The type attribute indicates the type of constraint that is being queried for, with a default of Any, meaning both content and attachment constraints will be searched. + + + + + + + + + ProvisionAgreementWhereType defines the parameters of a provision agreement query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + StructureUsage is used to indicate which structure usage the provision agreement must reference in order to constitute a match. + + + + + DataProvider is used to indicate which data provider the provision agreement must reference in order to constitute a match. + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryReportingTaxonomy.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryReportingTaxonomy.xsd new file mode 100644 index 0000000..a371fad --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryReportingTaxonomy.xsd @@ -0,0 +1,107 @@ + + + + + + + + SDMX Reporting Taxonomy Query Module + The reporting taxonomy query module provides the construct of a query for a reporting taxonomy. + + + + + ReportingTaxonomyQueryType defines the structure of a reporting taxonomy query. The parameters for the query are contained in the ReportingTaxonomyWhere element. The References element is used to indicate how objects that are referenced from the reporting taxonomy should be returned. + + + + + + + + + + + + + + ReportingTaxonomyWhere contains the parameters for a reporting taxonomy query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to search for a reporting taxonomy based on the details of its reporting categories. In any case, the reporting taxonomy will be returned according the indicated return detail. + + + + + + ReportingTaxonomyWhereType defines the parameters of a reporting taxonomy query. All supplied parameters must be matched in order for an object to satisfy the query. In addition to querying based on the base maintainable parameters, it is also possible to search for taxonomies that contain particular reporting categories, and on the root level structure definitions of the taxonomy. + + + + + + + + + + + + + + + + + + + + + + + + + + ReportingCategoryWhere is used to query for reporting categories matching the parameters supplied. It allows for nested reporting category queries so that hierarchical reporting categories can be queried explicitly by their nested level, although a top level reporting category will always result in a search for reporting categories at any level. This is an implicit set of "and" parameters, meaning all of the conditions must be met in order to return a match. + + + + + + ReportingCategoryWhereBaseType is an abstract base type that forms the basis for the ReportingCategoryQueryType. + + + + + + + + + + + + + + + + + + + + + ReportingCategoryWhereType contains a set of parameters for matching a reporting category. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + ProvisioningMetadata is used to query for a reporting category where the structure usages referenced are referenced by the reporting category. + + + + + StructuralMetadata is used to query for a reporting category where the structures referenced are referenced by the reporting category. + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQuerySchema.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQuerySchema.xsd new file mode 100644 index 0000000..e435943 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQuerySchema.xsd @@ -0,0 +1,57 @@ + + + + + + + SDMX Schema Query Module + The schema query module provides the construct of a query for data structure or metadata structure definition specific schemas. + + + + + DataSchemaQueryType defines the structure of a query for a structured data schema. This query consists of a single data structure which provides the full details of what type of structured data schema should be returned. + + + + + DataStructure references a data structure either explicitly or through a usage (dataflow) or agreement based on the flow (provision agreement). An observation dimension must be specifies as well as indicators for using explicit measures, deriving the type from the time series specific data set, and processing constraints. The explicit measure option is only applicable if the observation dimension is the measure dimension; otherwise the value provided will be ignored. The time series option is only applicable if the observation dimension is the time dimension; otherwise the value provided will be ignored. Constraints will only be applied in the returned schemas if specifically requested. This means that even if the request specifies a provision agreement, the returned schema will not take into account the constraints on that agreement unless the request explicitly requests this. + + + + + + + + MetadataSchemaQueryType defines the structure of a query for a structured metadata schema. This query consists of a single metadata structure which simply provides a reference to a metadata structure. + + + + + MetadataStructure references a metadata structure either explicitly or through it usage (metadataflow) or an application of that usage (provision agreement). + + + + + + + + DataStructureRequestType extends the base DataStructureRequestType to add additional parameters that are necessary when querying for a schema. + + + + + + The timeSeries attribute indicates that the requested schema should derived from the time series specific data set. If the observation dimension is anything but the time dimension, this field will be ignored. + + + + + The processConstraints attribute indicates that constraints should be processed when returning the schema. If this value is false, then the schema will be based on the data structure deflation, regardless of whether the reference was specified as a provision agreement, dataflow, or data structure. If this is true, then the constraints at the requested level will be processed and the returned schema will take these constraints into account (i.e. the appropriate code lists will be sub-setted + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryStructureSet.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryStructureSet.xsd new file mode 100644 index 0000000..98e700a --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryStructureSet.xsd @@ -0,0 +1,157 @@ + + + + + + + + SDMX Structure Set Query Module + The structure set query module provides the construct of a query for a structure set. + + + + + StructureSetQueryType defines the structure of a structure set query. The parameters for the query are contained in the StructureSetWhere element. The References element is used to indicate how objects that are referenced from the structure set should be returned. + + + + + + + + + + + + + + StructureSetWhere contains the parameters for a structure query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to search based on the structures that are related by the set or the objects which are mapped by the set's maps. In any case, the structure set will be returned according the indicated return detail. + + + + + + StructureSetWhereBaseType is an abstract base type which forms the basis for the StructureSetWhereType. + + + + + + + + + + + + + + + + + + The type attribute indicates the type of constraint that is being queried for, with a default of Any, meaning both content and attachment constraints will be searched. + + + + + + + + + StructureSetWhereType defines the parameters of a structure set query. All supplied parameters must be matched in order for an object to satisfy the query. In addition to querying based on the base maintainable parameters, it is also possible to search based on the structures that are related by the set or the objects which are mapped by the set's maps. + + + + + + + RelatedStructure is used to query for structure sets where the referenced key families, metadata structure definitions, dataflows, and metadataflows are related to another by the structure set. + + + + + MappedObject is used to query for structure sets where the reference object is mapped in one of the maps defined by the structure set. The referenced object can be specified as being either a source, a target, or either in the queried map. + + + + + + + + + + MappedObjectType defines a structure for referencing an object and indicating whether it is the source, target, or either for the purposes of query for structure set containing the referenced object in one of the maps it defines. + + + + + + The type attribute indicates whether the referenced object should be queried as the source, target, or both of a map. + + + + + + + + + MappedObjectReferenceType is a type for referencing any mappable object. It consists of a URN and/or a complete set of reference fields; agency, id, and version. + + + + + + + + + + + + + + + + + MappedObjectRefType defines a set of reference fields for any type of mappable object. + + + + + + + + + + + + MappedObjectTypeCodelistType is a restriction of the MaintainableTypeCodelistType which contains only the object types which can be mapped in a structure set. + + + + + + + + + + + + + + + + + + + + + SourceTargetType is an enumeration to indicate whether an object is the source, target, or either of the two options. + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryStructures.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryStructures.xsd new file mode 100644 index 0000000..4bc3c16 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryStructures.xsd @@ -0,0 +1,55 @@ + + + + + + + + SDMX Structures Query Module + The structures query module provides the construct of a query for all structures, regardless of their type. + + + + + StructuresQueryType defines the structure of a structures query. The parameters for the query are contained in the StructuresWhere element. The References element, typically used to indicate which objects should be returned, is fixed so that all object matching the parameters are returned.. + + + + + + + + + + + + + + StructuresWhere defines the parameters for a structures query. All parameters must be matched for an object to satisfy the query. Only the basic maintainable parameters are available. + + + + + + StructuresWhereType contains a set of parameters for a structures query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryTransformation.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryTransformation.xsd new file mode 100644 index 0000000..b65b108 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXQueryTransformation.xsd @@ -0,0 +1,495 @@ + + + + + + + + SDMX Transformation Query Module + The transformation query module provides the construct of a query for a transformation and related artefacts. + + + + + DefinitionSchemeWhereType is an abstract base type that extends and item scheme query to add the ability to query based on the VTL version. + + + + + + + Allows querying based on the VTL version number. + + + + + + + + + + TransformationSchemeQueryType defines the structure of a transformation scheme query. The parameters for the query are contained in the TransformationSchemeWhere element. The References element is used to indicate how objects that are referenced from the matched transformation scheme should be returned. + + + + + + + + + + + + + + TransformationSchemeWhere contains the parameters for a transformation scheme query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to query based on the details of the transformations defined within the scheme. + + + + + + TransformationSchemeWhereBaseType is an abstract base type which forms the basis for the TransformationSchemeWhereType. + + + + + + + + + + + + + + + + + + + + + + + + + + + TransformationSchemeWhereType defines the parameters of a transformation scheme query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + VtlMappingScheme is used to query for a transformation scheme based on the VTL mapping scheme that is used in the transformations. + + + + + NamePersonalisationScheme is used to query for a transformation scheme based on the name personalisation scheme that is used in the transformations. + + + + + CustomTypeScheme is used to query for a transformation scheme based on the custom type scheme that is used in the transformations. + + + + + RulesetScheme is used to query for a transformation scheme based on the ruleset scheme that is used in the transformations. + + + + + UserDefinedOperatorScheme is used to query for a transformation scheme based on the user defined operator scheme that is used in the transformations. + + + + + + + + + + TransformationWhere is used to query for transformations matching the parameters supplied. This is an implicit set of "and" parameters, meaning all of the conditions must be met in order to return a match. + + + + + + TransformationWhereBaseType is an abstract base type that forms the basis for the TransformationWhereType. + + + + + + + + + + + + + + + + TransformationWhereType defines a set of parameters for matching a transformation. All supplied parameters must be matched in order for an object to satisfy the query. In addition to the base parameters for an item, a transformation can be queried based on identifiable artefacts that are used in the expression. + + + + + + + IdentifiableArtefact allows a transformation to be queried based on the identifiable artefact it uses in its expression. + + + + + + + + + + VtlMappingSchemeQueryType defines the structure of a VTL mapping scheme query. The parameters for the query are contained in the VtlMappingSchemeWhere element. The References element is used to indicate how objects that are referenced from the matched VTL mapping scheme should be returned. + + + + + + + + + + + + + + VtlMappingSchemeWhere contains the parameters for a VTL mapping scheme query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to query based on the details of the VTL mappings defined within the scheme. + + + + + + VtlMappingSchemeWhereType defines the parameters of a VTL mapping scheme query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + + + + + + + + + + + VtlMappingWhere is used to query for VTL mappings matching the parameters supplied. This is an implicit set of "and" parameters, meaning all of the conditions must be met in order to return a match. + + + + + + VtlMappingWhereType defines a set of parameters for matching a VTL mapping. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + NamePersonalisationSchemeQueryType defines the structure of a name personalisation scheme query. The parameters for the query are contained in the NamePersonalisationSchemeWhere element. The References element is used to indicate how objects that are referenced from the matched name personalisation scheme should be returned. + + + + + + + + + + + + + + NamePersonalisationSchemeWhere contains the parameters for a name personalisation scheme query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to query based on the details of the name personalisations defined within the scheme. + + + + + + NamePersonalisationSchemeWhereType defines the parameters of a name personalisation scheme query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + + + + + + + + + + + + NamePersonalisationWhere is used to query for name personalisations matching the parameters supplied. This is an implicit set of "and" parameters, meaning all of the conditions must be met in order to return a match. + + + + + + NamePersonalisationWhereType defines a set of parameters for matching a name personalisation. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + RulesetSchemeQueryType defines the structure of a ruleset scheme query. The parameters for the query are contained in the RuleSetSchemeWhere element. The References element is used to indicate how objects that are referenced from the matched ruleset scheme should be returned. + + + + + + + + + + + + + + RulesetSchemeWhere contains the parameters for a ruleset scheme query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to query based on the details of the rulesets defined within the scheme. + + + + + + RulesetSchemeWhereType defines the parameters of a ruleset scheme query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + + + + + + + + + + + + RulesetWhere is used to query for rulesets matching the parameters supplied. This is an implicit set of "and" parameters, meaning all of the conditions must be met in order to return a match. + + + + + + RulesetWhereType defines a set of parameters for matching a ruleset. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + UserDefinedOperatorSchemeQueryType defines the structure of a user defined operator scheme query. The parameters for the query are contained in the UserDefinedOperatorSchemeWhere element. The References element is used to indicate how objects that are referenced from the matched user defined operator scheme should be returned. + + + + + + + + + + + + + + UserDefinedOperatorSchemeWhere contains the parameters for a user defined operator scheme query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to query based on the details of the user defined operators defined within the scheme. + + + + + + UserDefinedOperatorSchemeWhereType defines the parameters of a user defined operator scheme query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + + + + + + + + + + + + UserDefinedOperatorWhere is used to query for user defined operators matching the parameters supplied. This is an implicit set of "and" parameters, meaning all of the conditions must be met in order to return a match. + + + + + + UserDefinedOperatorWhereType defines a set of parameters for matching a user defined operator. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + CustomTypeSchemeQueryType defines the structure of a custom type scheme query. The parameters for the query are contained in the CustomTypeSchemeWhere element. The References element is used to indicate how objects that are referenced from the matched custom type scheme should be returned. + + + + + + + + + + + + + + CustomTypeSchemeWhere contains the parameters for a custom type scheme query. All parameters must be matched for an object to satisfy the query. In addition to querying based on the basic maintainable properties, it is also possible to query based on the details of the custom types defined within the scheme. + + + + + + CustomTypeSchemeWhereType defines the parameters of a custom type scheme query. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + + + + + + + + + + + + + + + CustomTypeWhere is used to query for custom types matching the parameters supplied. This is an implicit set of "and" parameters, meaning all of the conditions must be met in order to return a match. + + + + + + CustomTypeWhereType defines a set of parameters for matching a custom type. All supplied parameters must be matched in order for an object to satisfy the query. + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructure.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructure.xsd new file mode 100644 index 0000000..36e3aee --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructure.xsd @@ -0,0 +1,685 @@ + + + + + + + + + + + + + + + + + + + + + + + SDMX Structure Namespace Module + The structure namespace module contains the descriptions of structural metadata such as key families, concepts, and codelists. For convenience, this module has been broken down into sub-modules for the different type of structural constructs. + + + + + Structures contains constructs for all structural metadata components. + + + + + + StructuresType describes the structure of the container for all structural metadata components. The structural components may be explicitly detailed, or referenced from an external structure document or registry service. Best practices dictate that, at a minimum, any structural component that is referenced by another structural component be included by reference. + + + + + OrganisationSchemes contains a collection of organisation scheme descriptions. The organisation schemes may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Dataflows contains a collection of data flow descriptions. The data flows may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + Metadataflows contains a collection of metadata flow descriptions. The metadata flows may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + CategorySchemes contains a collection of category scheme descriptions. The category schemes may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + Categorisations contains a collection of structural object categorisations. This container may contain categorisations for many types of objects. The categorisations may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + Codelists contains a collection of code list descriptions. The code lists may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + HierarchicalCodelists contains a collection of hierarchical code list descriptions. The hierarchical code lists may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + Concepts contains a collection of concept descriptions. The concepts described are contained within schemes. The concepts may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + MetadataStructures contains a collection of metadata structure definition descriptions. The metadata structure definitions may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + DataStructures contains a collection of data structure definitions. The data structure definitions may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + StructureSets contains a collection of structure set descriptions. The structure sets may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + ReportingTaxonomies contains a collection of reporting taxonomy descriptions. The reporting taxonomies may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + Processes contains a collection of process descriptions. The processes may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + Constraints contains a collection of constraint descriptions. This container may contain both attachment and content constraints. The constraints may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + + + + + + + ProvisionAgreements contains a collection of provision agreements. The provision agreements may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + CustomTypes contains a collection of custom type schemes. The scheme may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + VtlMappings contains a collection of VTL mapping schemes. The scheme may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + NamePersonalisations contains a collection of name personalisation schemes. The scheme may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + Rulsets contains a collection of ruleset schemes. The scheme may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + Transformations contains a collection of transformation schemes. The transformation schemes may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + UserDefinedOperators contains a collection of user defined operator schemes. The scheme may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + + + + OrganisationSchemesType describes the structure of the organisation schemes container. It contains one or more organisation scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + AgencyScheme provides the details of an agency scheme, in which agencies are described. + + + + + + + + + DataConsumerScheme provides the details of an data consumer scheme, in which data consumers are described. + + + + + + + + + DataProviderScheme provides the details of an data provider scheme, in which data providers are described. + + + + + + + + + OrganisationUnitScheme provides the details of an organisation unit scheme, in which organisation units are described. + + + + + + + + + + + + DataflowsType describes the structure of the data flows container. It contains one or more data flow, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + Dataflow provides the details of a data flow, which is defined as the structure of data that will be provided for different reference periods. + + + + + + + + MetadataflowsType describes the structure of the metadata flows container. It contains one or more metadata flow, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + Metadataflow provides the details of a metadata flow, which is defined as the structure of reference metadata that will be provided for different reference periods + + + + + + + + CategorySchemesType describes the structure of the category schemes container. It contains one or more category scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + CategoryScheme provides the details of a category scheme, which is the descriptive information for an arrangement or division of categories into groups based on characteristics, which the objects have in common. This provides for a simple, leveled hierarchy or categories. + + + + + + + + + + + + CategorisationsType describes the structure of the categorisations container. It contains one or more categorisation of a specific object type, which can be explicitly detailed or referenced from an external structure document or registry service. This container may contain categorisations for multiple types of structural objects. + + + + + Categorisation allows for the association of an identifiable object to a category, providing for the classifications of the reference identifiable object. This must either contain the full details of the categorisation, or provide a name and identification information and reference the full details from an external structure document or registry service. + + + + + + + + CodelistsType describes the structure of the code lists container. It contains one or more code list, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + Codelist provides the details of a code list, which is defined as a list from which some statistical concepts (coded concepts) take their values. + + + + + + + + + + + + HierarchicalCodelistsType describes the structure of the hierarchical code lists container. It contains one or more hierarchical code list, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + HierarchicalCodelist provides the details of a hierarchical code list, which is defined as an organised collection of codes that may participate in many parent/child relationships with other codes in the list, as defined by one or more hierarchy of the list. + + + + + + + + + + + + + + + + ConceptsType describes the structure of the concepts container. It contains one or more concept schemes, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + ConceptScheme provides the details of a concept scheme, which is the descriptive information for an arrangement or division of concepts into groups based on characteristics, which the objects have in common. It contains a collection of concept definitions, that may be arranged in simple hierarchies. + + + + + + + + + + + + MetadataStructuresType describes the structure of the metadata structure definitions container. It contains one or more metadata structure definition, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + MetadataStructure provides the details of a metadata structure definition, which is defined as a collection of metadata concepts, their structure and usage when used to collect or disseminate reference metadata. A metadata structure definition performs several functions: it groups sets of objects into "targets" against which reference metadata may be reported. Targets define the structure of the reference metadata "keys" which identify specific types of reported metadata, and describe the valid values for populating the keys. Also, metadata structure definitions provide a presentational organization of concepts for reporting purposes. The structure of a reference metadata report is derived from this presentational structure. + + + + + + + + DataStructuresType describes the structure of the data structure definitions container. It contains one or more data structure definition, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + DataStructure provides the details of a data structure definition, which is defined as a collection of metadata concepts, their structure and usage when used to collect or disseminate data. + + + + + + + + StructureSetsType describes the structure of the structure sets container. It contains one or more structure set, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + StructureSet provides the details or a structure set, which allows components in one structure, structure usage, or item scheme to be mapped to components in another structural component of the same type. + + + + + + + + + + + + + + + + + + + + + + + + + + + + ReportingTaxonomiesType describes the structure of the reporting taxonomies container. It contains one or more reporting taxonomy, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + ReportingTaxonomy provides the details of a reporting taxonomy, which is a scheme which defines the composition structure of a data report where each component can be described by an independent data or metadata flow definition. + + + + + + + + + + + + ProcessesType describes the structure of the processes container. It contains one or more process, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + Process provides the details of a process, which is a scheme which defines or documents the operations performed on data in order to validate data or to derive new information according to a given set of rules. It is not meant to support process automation, but serves as a description of how processes occur. The primary use for this structural mechanism is the attachment of reference metadata regarding statistical processing. This must either contain the full details of the category scheme, or provide a name and identification information and reference the full details from an external structure document or registry service. + + + + + + + + + + + + + + + + ConstraintsType describes the structure of the constraints container. It contains one or more constraint, which can be explicitly detailed or referenced from an external structure document or registry service. This container may contain both attachment and content constraints. + + + + + AttachmentConstraint describes sub sets of the content of a data or metadata set in terms of the content regions or in terms of the set of key combinations to which attributes or reference metadata (as defined by structure definitions) may be attached. + + + + + ContentConstraint specifies a sub set of the definition of the allowable or available content of a data or metadata set in terms of the content or in terms of the set of key combinations. + + + + + + + + ProvisionAgreementsType describes the structure of the provision agreements container. It contains one or more provision agreement, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + ProvisionAgreement provides the details of a provision agreement, which is an agreement for a data provider to report data or reference metadata against a flow. + + + + + + + + CustomTypesType describes the structure of the custom type schemes container. It contains one or more custom type scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + CustomTypeScheme provides the details of a custom type scheme, in which user defined operators are described. + + + + + + + + + + + + VtlMappingsType describes the structure of the VTL mappings schemes container. It contains one or more VTL mapping schemes, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + VtlMappingScheme provides the details of a VTL mapping scheme, in which VTL mappings are described. + + + + + + + + + + + + + + + + NamePersonalisationsType describes the structure of the name personalisation schemes container. It contains one or more name personalisation scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + NamePersonalisationScheme provides the details of a name personalisation scheme, in which name personalisations are described. + + + + + + + + + + + + RulesetsType describes the structure of the ruleset schemes container. It contains one or more ruleset scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + RulesetScheme provides the details of a ruleset scheme, in which rulesets are described. + + + + + + + + + + + + TransformationsType describes the structure of the transformations container. It contains one or more transformation schemes, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + TransformationScheme provides the details of a transformation scheme, in which transformations are described. + + + + + + + + + + + + UserDefinedOperatorsType describes the structure of the user defined operator schemes container. It contains one or more user defined operator scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + UserDefinedOperatorScheme provides the details of a user defined operator scheme, in which user defined operators are described. + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureBase.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureBase.xsd new file mode 100644 index 0000000..b2791f0 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureBase.xsd @@ -0,0 +1,574 @@ + + + + + + + SDMX Base Structure Module + The base structure module contains the descriptions of base structural metadata constructs, such as item schemes, structures, and structure usages, as well as constructs reused by multiple types of structural components. + + + + + IdentifiableType is an abstract base type for all identifiable objects. + + + + + + The id is the identifier for the object. + + + + + The urn attribute holds a valid SDMX Registry URN (see SDMX Registry Specification for details). + + + + + The uri attribute holds a URI that contains a link to a resource with additional information about the object, such as a web page. This uri is not a SDMX message. + + + + + + + + + NameableType is an abstract base type for all nameable objects. + + + + + + + Name provides for a human-readable name for the object. This may be provided in multiple, parallel language-equivalent forms. + + + + + Description provides for a longer human-readable description of the object. This may be provided in multiple, parallel language-equivalent forms. + + + + + + + + + + VersionableType is an abstract base type for all versionable objects. + + + + + + This version attribute holds a version number in the format of #[.#]+ (see com:VersionType definition for details). If not supplied, the version number is defaulted to 1.0. + + + + + The validFrom attribute provides the inclusive start date for providing supplemental validity information about the version. + + + + + The validTo attribute provides the inclusive end date for providing supplemental validity information about the version. + + + + + + + + + MaintainableBaseType is an abstract type that only serves the purpose of forming the base for the actual MaintainableType. The purpose of this type is to restrict the VersionableType to require the id attribute. + + + + + + + + + + + + + + + + MaintainableType is an abstract base type for all maintainable objects. + + + + + + The agencyID must be provided, and identifies the maintenance agency of the object. + + + + + The isFinal attribute indicates whether the object is unchangeable without versioning. If the value is true, the object must be versioned upon change. If the final attribute is not supplied, then the object is assumed not to be final. Note that all production objects must be final. + + + + + The isExternalReference attribute, if true, indicates that the actual object is not defined the corresponding element, rather its full details are defined elsewhere - indicated by either the registryURL, the repositoryURL, or the structureURL. The purpose of this is so that each structure message does not have to redefine object that are already defined elsewhere. If the isExternalReference attribute is not set, then it is assumed to be false, and the object should contain the full definition of its contents. If more than one of the registryURL, the repositoryURL, and the structureURL are supplied, then the application processing the object can choose the method it finds best suited to retrieve the details of the object. + + + + + + + + + + ItemSchemeType is an abstract base type for all item scheme objects. It contains a collection of items. Concrete instances of this type should restrict the actual types of items allowed within the scheme. + + + + + + + + + + + The isPartial, if true, indicates that only the relevant portion of the item scheme is being communicated. This is used in cases where a codelist is returned for a key family in the context of a constraint. + + + + + + + + + Item is an abstract element that serves as a substitution head for all items in an item scheme, including those items nested within other items. Concrete instances of this must use a concrete instance of ItemType. + + + + + + ItemBaseType is an abstract base type that forms the basis for the ItemType. It requires that at least an id be supplied for an item. + + + + + + + + + + + + + + + + ItemType is an abstract base type for all items with in an item scheme. Concrete instances of this type may or may not utilize the nested item, but if so should restrict the actual types of item allowed. + + + + + + + + + + + + + + + + UnnestedItemType is an abstract base type for all items with in an item scheme that do not contain nexted items. + + + + + + + + + + + + + + + StructureType is an abstract base type for all structure objects. Concrete instances of this should restrict to a concrete grouping. + + + + + + + + + + + + + + + Grouping is an abstract element that serves as a substitution head for all structure groupings. Groupings contain a collection of component lists for a structure. Concrete instances of this must use a concrete instance of GroupingType. + + + + + + GroupType is an abstract base type for specific structure groupings. It contains a collection of component lists. Concrete instances of this should restrict to specific concrete component lists. + + + + + + + + + + + ComponentList is an abstract element that serves as a substitution head for all component lists. Concrete instances of this must use a concrete instance of ComponentListType. + + + + + + ComponentListType is an abstract base type for all component lists. It contains a collection of components. Concrete types should restrict this to specific concrete components. + + + + + + + + + + + + + + + Component is an abstract element that serves as a substitution head for all components. Concrete instances of this must use a concrete instance of ComponentType. + + + + + + ComponentBaseType is an abstract type that only serves the purpose of forming the base for the actual ComponentType. It only restricts the format of the id attribute to the NCNameIDType. + + + + + + + + + The id attribute holds an explicit identification of the component. If this identifier is not supplied, then it is assumed to be the same as the identifier of the concept referenced from the concept identity. Because structures require that every component be given a unique identifier, it may be necessary to assign an explicit identifier when more than one component in a structure reference concepts with same identifier. It is important to note that this applies strictly to the identifier of concept and not the URN. Therefore if two concepts with the same identifier from different concept schemes are referenced in the same structure, one of the components will have to provide a unique explicit identifier. The type of this identifier is restricted to the com:NCNameIDType. This is necessary, since component identifiers are used to create XML elements and attributes in data and metadata structure specific schemas and therefore must be compliant with the NCName type in XML Schema (see com:NCNameIDType for further details). + + + + + + + + + ComponentType is an abstract base type for all components. It contains information pertaining to a component, including an optional reference to a concept, an optional role played by the concept, an optional text format description, and an optional local representation. + + + + + + + ConceptIdentity allows for the referencing of a concept in a concept scheme. The component takes its semantic from this concept, and if an id is not specified, it takes its identification as well. If a representation (LocalRepresentation) is not supplied, then the representation of the component is also inherited from the concept. Note that in the case of the component representation being inherited from the concept, the allowable representations for the component still apply. Therefore, if a component references a concept with a core representation that is not allowed for the concept, that representation must be locally overridden. For components which can specify a concept role, it is implied that the concept which is referenced also identifies a role for the component. + + + + + LocalRepresentation references item schemes that may be used to create the representation of a component. The type of this must be refined such that a concrete item scheme reference is used. + + + + + + + + + + StructureUsageType is an abstract base type for all structure usages. It contains a reference to a structure. Concrete instances of this type should restrict the type of structure referenced. + + + + + + + Structure references the structure (data structure or metadata structure definition) which the structure usage is based upon. Implementations will have to refine the type to use a concrete structure reference (i.e. either a data structure or metadata structure definition reference). + + + + + + + + + + UsageStatusType provides a list of enumerated types for indicating whether reporting a given attribute is mandatory or conditional. + + + + + Reporting the associated attribute is mandatory - a value must be supplied. + + + + + Reporting the associated attribute is not mandatory - a value may be supplied, but is not required. + + + + + + + + RepresentationType is an abstract type that defines a representation. Because the type of item schemes that are allowed as the an enumeration vary based on the object in which this is defined, this type is abstract to force that the enumeration reference be restricted to the proper type of item scheme reference. + + + + + TextFormat describes an uncoded textual format. + + + + + + Enumeration references an item scheme that enumerates the allowable values for this representation. + + + + + EnumerationFormat describes the facets of the item scheme enumeration. This is for the most part, informational. + + + + + + + + + TextFormatType defines the information for describing a full range of text formats and may place restrictions on the values of the other attributes, referred to as "facets". + + + + The textType attribute provides a description of the datatype. If it is not specified, any valid characters may be included in the text field (it corresponds to the xs:string datatype of W3C XML Schema) within the constraints of the facets. + + + + + The isSequence attribute indicates whether the values are intended to be ordered, and it may work in combination with the interval, startValue, and endValue attributes or the timeInterval, startTime, and endTime, attributes. If this attribute holds a value of true, a start value or time and a numeric or time interval must supplied. If an end value is not given, then the sequence continues indefinitely. + + + + + The interval attribute specifies the permitted interval (increment) in a sequence. In order for this to be used, the isSequence attribute must have a value of true. + + + + + The startValue attribute is used in conjunction with the isSequence and interval attributes (which must be set in order to use this attribute). This attribute is used for a numeric sequence, and indicates the starting point of the sequence. This value is mandatory for a numeric sequence to be expressed. + + + + + The endValue attribute is used in conjunction with the isSequence and interval attributes (which must be set in order to use this attribute). This attribute is used for a numeric sequence, and indicates that ending point (if any) of the sequence. + + + + + The timeInterval attribute indicates the permitted duration in a time sequence. In order for this to be used, the isSequence attribute must have a value of true. + + + + + The startTime attribute is used in conjunction with the isSequence and timeInterval attributes (which must be set in order to use this attribute). This attribute is used for a time sequence, and indicates the start time of the sequence. This value is mandatory for a time sequence to be expressed. + + + + + The endTime attribute is used in conjunction with the isSequence and timeInterval attributes (which must be set in order to use this attribute). This attribute is used for a time sequence, and indicates that ending point (if any) of the sequence. + + + + + The minLength attribute specifies the minimum and length of the value in characters. + + + + + The maxLength attribute specifies the maximum length of the value in characters. + + + + + The minValue attribute is used for inclusive and exclusive ranges, indicating what the lower bound of the range is. If this is used with an inclusive range, a valid value will be greater than or equal to the value specified here. If the inclusive and exclusive data type is not specified (e.g. this facet is used with an integer data type), the value is assumed to be inclusive. + + + + + The maxValue attribute is used for inclusive and exclusive ranges, indicating what the upper bound of the range is. If this is used with an inclusive range, a valid value will be less than or equal to the value specified here. If the inclusive and exclusive data type is not specified (e.g. this facet is used with an integer data type), the value is assumed to be inclusive. + + + + + The decimals attribute indicates the number of characters allowed after the decimal separator. + + + + + The pattern attribute holds any regular expression permitted in the similar facet in W3C XML Schema. + + + + + The isMultiLingual attribute indicates for a text format of type "string", whether the value should allow for multiple values in different languages. + + + + + + + BasicComponentTextFormatType is a restricted version of the TextFormatType that restricts the text type to the representations allowed for all components except for target objects. + + + + + + + + + + + SimpleComponentTextFormatType is a restricted version of the BasicComponentTextFormatType that does not allow for multi-lingual values. + + + + + + + + + + + + CodededTextFormatType is a restricted version of the SimpleComponentTextFormatType that only allows factets and text types applicable to codes. Although the time facets permit any value, an actual code identifier does not support the necessary characters for time. Therefore these facets should not contain time in their values. + + + + + + + + + + + + + + + + + + + + + + + + CodeDataType is a restriction of the basic data types that are applicable to codes. Although some of the higher level time period formats are perimitted, it should be noted that any value which contains time (which includes a time zone offset) is not allowable as a code identifier. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NonFacetedTextFormatType is a restricted version of the SimpleComponentTextFormatType that does not allow for any facets. + + + + + + + + + + + + + + + + + + + + + + + + TimeTextFormat is a restricted version of the SimpleComponentTextFormatType that only allows time based format and specifies a default ObservationalTimePeriod representation and facets of a start and end time. + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureCategorisation.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureCategorisation.xsd new file mode 100644 index 0000000..501980f --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureCategorisation.xsd @@ -0,0 +1,34 @@ + + + + + + + + SDMX Categorisation Structure Module + The categorisation structure module defines the structure categorisation constructs. + + + + + CategorisationType is defines the structure for a categorisation. A source object is referenced via an object reference and the target category is referenced via the target category. + + + + + + + Source is a reference to an object to be categorized. + + + + + Target is reference to the category that the referenced object is to be mapped to. + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureCategory.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureCategory.xsd new file mode 100644 index 0000000..5660a8c --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureCategory.xsd @@ -0,0 +1,65 @@ + + + + + + + + SDMX Category Structure Module + The category structure module defines the structure of category scheme and category constructs. + + + + + CategorySchemeType describes the structure of a category scheme. A category scheme is the descriptive information for an arrangement or division of categories into groups based on characteristics, which the objects have in common. This provides for a simple, leveled hierarchy or categories. + + + + + + + + + + + + + + The id attribute holds the identification of the category scheme. The type of this id is restricted to the com:NCNNameIDType. This is necessary, since the category scheme may be used to create simple types in data and metadata structure specific schemas and therefore must be compliant with the NCName type in XML Schema (see com:NCNameIDType for further details). + + + + + + + + + Category represents a set of nested categories which describe a simple classification hierarchy. + + + + + + + + + + CategoryType describes the details of a category. A category is defined as an item at any level in a classification. The Category element represents a set of nested categories which are child categories. + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureCodelist.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureCodelist.xsd new file mode 100644 index 0000000..b422b39 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureCodelist.xsd @@ -0,0 +1,71 @@ + + + + + + + + SDMX Code List Structure Module + The code list structure module defines the structure of code list and code constructs. + + + + + CodelistType defines the structure of a codelist. A codelist is defined as a list from which some statistical concepts (coded concepts) take their values. + + + + + + + + + + + + + + The id attribute holds the identification of the code list. The type of this id is restricted to the com:NCNNameIDType. This is necessary, since the code list may be used to create simple types in data and metadata structure specific schemas and therefore must be compliant with the NCName type in XML Schema (see com:NCNameIDType for further details). + + + + + + + + + Code describes a code in a codelist. In addition to the identification and description of the code, basic presentational information is also available. Presentational information not present may be added through the use of annotations. + + + + + + CodeType describes the structure of a code. A code is defined as a language independent set of letters, numbers or symbols that represent a concept whose meaning is described in a natural language. Presentational information not present may be added through the use of annotations. + + + + + + + + Name provides for a human-readable name for the object. This may be provided in multiple, parallel language-equivalent forms. It may be used in place of a short description. + + + + + Description provides a plain text, human-readable description of the code. This may be provided in multiple, parallel language-equivalent forms. + + + + + + Parent provides the ability to describe simple hierarchies within a single codelist, by referencing the id value of another code in the same codelist. + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureConcept.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureConcept.xsd new file mode 100644 index 0000000..00845b6 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureConcept.xsd @@ -0,0 +1,122 @@ + + + + + + + + SDMX Concept Structure Module + The concept structure module defines the structure of concept scheme and concept constructs. + + + + + ConceptSchemeType describes the structure of a concept scheme. A concept scheme is the descriptive information for an arrangement or division of concepts into groups based on characteristics, which the objects have in common. It contains a collection of concept definitions, that may be arranged in simple hierarchies. + + + + + + + + + + + + + + The id attribute holds the identification of the concept scheme. The type of this id is restricted to the com:NCNNameIDType. This is necessary, since the concept scheme may be used to create simple types in data and metadata structure specific schemas and therefore must be compliant with the NCName type in XML Schema (see com:NCNameIDType for further details). + + + + + + + + + Concept describes the details of a concept within a concept scheme. + + + + + + ConceptBaseType is an abstract base type the forms the basis of the ConceptType by requiring a name and id, and restricting the content of the id. + + + + + + + + + + + Parent captures the semantic relationships between concepts which occur within a single concept scheme. This identifies the concept of which the current concept is a qualification (in the ISO 11179 sense) or subclass. + + + + + + + The id attribute holds the identification of the concept. The type of this id is restricted to the com:NCNNameIDType. This is necessary, since concept id may be used to create XML elements and attributes in data and metadata structure specific schemas and therefore must be compliant with the NCName type in XML Schema (see com:NCNameIDType for further details). + + + + + + + + + ConceptType describes the details of a concept. A concept is defined as a unit of knowledge created by a unique combination of characteristics. If a concept does not specify a TextFormat or a core representation, then the representation of the concept is assumed to be represented by any set of valid characters (corresponding to the xs:string datatype of W3C XML Schema). + + + + + + + + + + + + Provides a reference to an ISO 11179 concept. + + + + + + + + + + ConceptRepresentation defines the core representation that are allowed for a concept. The text format allowed for a concept is that which is allowed for any non-target object component. + + + + + + + + + Enumeration references a codelist which enumerates the possible values that can be used as the representation of this concept. + + + + + + + + + + + + ISOConceptReferenceType provides a reference to and ISO 11179 concept. + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureConstraint.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureConstraint.xsd new file mode 100644 index 0000000..79b4123 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureConstraint.xsd @@ -0,0 +1,392 @@ + + + + + + + + SDMX Constraint Structure Module + The constraint structure module defines the structure of attachment and content constraint constructs. + + + + + ConstraintBaseType is an abstract base type that forms the basis of the main abstract ConstraintType. It requires that a name be provided. + + + + + + + + + + + + + + + ConstraintType is an abstract base type that specific types of constraints (content and attachment) restrict and extend to describe their details. The inclusion of a key or region in a constraint is determined by first processing the included key sets, and then removing those keys defined in the excluded key sets. If no included key sets are defined, then it is assumed the all possible keys or regions are included, and any excluded key or regions are removed from this complete set. + + + + + + + ConstraintAttachment describes the collection of constrainable artefacts that the constraint is attached to. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AttachmentConstraintType describes the details of an attachment constraint by defining the data or metadata key sets or component regions that attributes or reference metadata may be attached in the constraint attachment objects. + + + + + + + + + + + + + + + + + + + + ContentConstraintBaseType is an abstract base type that forms the basis for the ContentConstraintType. + + + + + + + + + + ConstraintAttachment describes the collection of constrainable artefacts that the constraint is attached to. + + + + + + DataKeySet defines a collection of full or partial data keys. + + + + + MetadataKeySet defines a collection of metadata keys. + + + + + CubeRegion describes a set of dimension values which define a region and attributes which relate to the region for the purpose of describing a constraint. + + + + + MetadataTargetRegion describes a set of target object values for a given report structure which define a region, and the metadata attribute which relate to the target for the purpose of describing a constraint. + + + + + + + + + + + ContentConstraintType describes the details of a content constraint by defining the content regions, key sets, or release information for the constraint attachment objects. Note that if the constraint is for a data provider, then only release calendar information is relevant, as there is no reliable way of determining which key family is being used to frame constraints in terms of cube regions or key sets. + + + + + + + ReleaseCalendar defines dates on which the constrained data is to be made available. + + + + + ReferencePeriod is used to report start date and end date constraints. + + + + + + The type attribute indicates whether this constraint states what data is actually present for the constraint attachment, or if it defines what content is allowed. The default value is "Actual", meaning the data actually present for the constraint attachment. + + + + + + + + + ReleaseCalendarType describes information about the timing of releases of the constrained data. All of these values use the standard "P7D" - style format. + + + + + Periodicity is the period between releases of the data set. + + + + + Offset is the interval between January first and the first release of data within the year. + + + + + Tolerance is the period after which the release of data may be deemed late. + + + + + + + + KeySetType is an abstract base type for defining a collection of keys. + + + + + Key contains a data or metadata key, which are sets of component values which identify the data or metadata. + + + + + + The isIncluded attribute indicates whether the keys defined in this key set are inclusive or exclusive to the constraint. + + + + + + + DataKeySetType defines a collection of full or partial data keys (dimension values). + + + + + + + Key contains a set of dimension values which identify a full set of data. + + + + + + + + + + MetadataKeySetType defines a collection of metadata keys (identifier component values). + + + + + + + Key contains a set of target object values for a specified report structure which serve to identify which object reference metadata conforming to the specified report structure is available for. + + + + + + + + + + ConstraintAttachmentType describes a collection of references to constrainable artefacts. + + + + + DataProvider is reference to a data provider to which the constraint is attached. If this is used, then only the release calendar is relevant. The referenced is provided as a URN and/or a full set of reference fields. + + + + + DataSet is reference to a data set to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. + + + + + MetadataSet is reference to a metadata set to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. + + + + + SimpleDataSource describes a simple data source, which is a URL of a SDMX-ML data or metadata message. + + + + + + + DataStructure is reference to a data structure definition to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. A constraint which is attached to more than one data structure must only express key sets and/or cube regions where the identifiers of the dimensions are common across all structures to which the constraint is attached. + + + + + QueryableDataSource describes a queryable data source to which the constraint is attached. + + + + + + + MetadataStructure is reference to a metadata structure definition to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. A constraint which is attached to more than one metadata structure must only express key sets and/or target regions where the identifiers of the target objects are common across all structures to which the constraint is attached. + + + + + QueryableDataSource describes a queryable data source to which the constraint is attached. + + + + + + + Dataflow is reference to a data flow to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. A constraint can be attached to more than one dataflow, and the dataflows do not necessarily have to be usages of the same data structure. However, a constraint which is attached to more than one data structure must only express key sets and/or cube regions where the identifiers of the dimensions are common across all structures to which the constraint is attached. + + + + + QueryableDataSource describes a queryable data source to which the constraint is attached. + + + + + + + Metadataflow is reference to a metadata flow to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. A constraint can be attached to more than one metadataflow, and the metadataflows do not necessarily have to be usages of the same metadata structure. However, a constraint which is attached to more than one metadata structure must only express key sets and/or target regions where the identifiers of the target objects are common across all structures to which the constraint is attached. + + + + + QueryableDataSource describes a queryable data source to which the constraint is attached. + + + + + + + ProvisionAgreementReference is reference to a provision agreement to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. A constraint can be attached to more than one provision aggreement, and the provision agreements do not necessarily have to be references structure usages based on the same structure. However, a constraint which is attached to more than one provision agreement must only express key sets and/or cube/target regions where the identifier of the components are common across all structures to which the constraint is attached. + + + + + QueryableDataSource describes a queryable data source to which the constraint is attached. + + + + + + + + + + AttachmentConstraintAttachmentType defines the structure for specifying the object to which an attachment constraints applies. + + + + + + + DataSet is reference to a data set to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. Multiple instance can only be used if they have the same underlying structure. + + + + + MetadataSet is reference to a metadata set to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. Multiple instance can only be used if they have the same underlying structure. + + + + + SimpleDataSource describes a simple data source, which is a URL of a SDMX-ML data or metadata message. Multiple instance can only be used if they have the same underlying structure. + + + + + + + + + + + + + + + + + ContentConstraintAttachmentType defines the structure for specifying the target object(s) of a content constraint. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureDataStructure.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureDataStructure.xsd new file mode 100644 index 0000000..6298c26 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureDataStructure.xsd @@ -0,0 +1,565 @@ + + + + + + + + SDMX Data Structure Structure Module + The Data Structure structure module defines the structure of data structure definition constructs. + + + + + DataStructureType describes the structure of a data structure definition. A data structure definition is defined as a collection of metadata concepts, their structure and usage when used to collect or disseminate data. + + + + + + + + + + + + + + + + + + DataStructureComponents defines the grouping of the sets of metadata concepts that have a defined structural role in the data structure definition. Note that for any component or group defined in a data structure definition, its id must be unique. This applies to the identifiers explicitly defined by the components as well as those inherited from the concept identity of a component. For example, if two dimensions take their identity from concepts with same identity (regardless of whether the concepts exist in different schemes) one of the dimensions must be provided a different explicit identifier. Although there are XML schema constraints to help enforce this, these only apply to explicitly assigned identifiers. Identifiers inherited from a concept from which a component takes its identity cannot be validated against this constraint. Therefore, systems processing data structure definitions will have to perform this check outside of the XML validation. There are also three reserved identifiers in a data structure definition; OBS_VALUE, TIME_PERIOD, and REPORTING_PERIOD_START_DAY. These identifiers may not be used outside of their respective defintions (PrimaryMeasure, TimeDimension, and ReportingYearStartDay). This applies to both the explicit identifiers that can be assigned to the components or groups as well as an identifier inherited by a component from its concept identity. For example, if an ordinary dimension (i.e. not the time dimension) takes its concept identity from a concept with the identifier TIME_PERIOD, that dimension must provide a different explicit identifier. + + + + + + + + + + DataStructureComponentsBaseType is an abstract base type the serves as the basis for the DataStructureComponentsType. This type is necessary to allow for valid substitutions of component lists. + + + + + + + + + + DataStructureComponentsType describes the structure of the grouping to the sets of metadata concepts that have a defined structural role in the data structure definition. At a minimum at least one dimension and a primary measure must be defined. + + + + + + + + + + + + + + + + AttributeList describes the attribute descriptor for the data structure definition. It is a collection of metadata concepts that define the attributes of the data structure definition. + + + + + + AttributeListBaseType is an abstract base type used as the basis for the AttributeListType. + + + + + + + + + The id attribute is provided in this case for completeness. However, its value is fixed to AttributeDescriptor. + + + + + + + + + AttributeListType describes the attribute descriptor for the data structure definition. + + + + + + + + + + + + + + Attribute describes the definition of a data attribute, which is defined as a characteristic of an object or entity. + + + + + + AttributeBaseType is an abstract base type that serves as the basis for the AttributeType. It restricts the text format base to a text format valid for data components (that does not allow for XHTML representation). The local representation is restricted to the values defined in codelist. The concept role is restricted to the values valid for a data attribute. + + + + + + + + + + + + + + + AttributeType describes the structure of a data attribute, which is defined as a characteristic of an object or entity. The attribute takes its semantic, and in some cases it representation, from its concept identity. An attribute can be coded by referencing a code list from its coded local representation. It can also specify its text format, which is used as the representation of the attribute if a coded representation is not defined. Neither the coded or uncoded representation are necessary, since the attribute may take these from the referenced concept. An attribute specifies its relationship with other data structure components and is given an assignment status. These two properties dictate where in a data message the attribute will be attached, and whether or not the attribute will be required to be given a value. A set of roles defined in concept scheme can be assigned to the attribute. + + + + + + + ConceptRole references concepts which define roles which this attribute serves. If the concept from which the attribute takes its identity also defines a role the concept serves, then the isConceptRole indicator can be set to true on the concept identity rather than repeating the reference here. + + + + + AttributeRelationship describes how the value of this attribute varies with the values of other components. These relationships will be used to determine the attachment level of the attribute in the various data formats. + + + + + + The assignmentStatus attribute indicates whether a value must be provided for the attribute when sending documentation along with the data. + + + + + + + + + AttributeRelationshipType defines the structure for stating the relationship between an attribute and other data structure definition components. + + + + + This means that value of the attribute will not vary with any of the other key family components. This will always be treated as a data set level attribute. + + + + + + This is used to reference dimensions in the data structure definition on which the value of this attribute depends. An attribute using this relationship can be either a group, series (or section), or observation level attribute. The attachment level of the attribute will be determined by the data format and which dimensions are referenced. + + + + + This is used to specify that the attribute should always be attached to the groups referenced here. Note that if one of the referenced dimensions is the time dimension, the groups referenced here will be ignored. + + + + + + This is used as a convenience to referencing all of the dimension defined by the referenced group. The attribute will also be attached to this group. + + + + + This is used to specify that the value of the attribute is dependent upon the observed value. An attribute with this relationship will always be treated as an observation level attribute. + + + + + + + + ReportingYearStartDay is a specialized data attribute which provides important context to the time dimension. If the value of the time dimension is one of the standard reporting periods (see com:ReportingTimePeriodType) then this attribute is used to state the month and day that the reporting year begins. This provides a reference point from which the actual calendar dates covered by these periods can be determined. If this attribute does not occur in a data set, then the reporting year start day will be assumed to be January 1. + + + + + + ReportingYearStartDayType defines the structure of the reporting year start day attribute. The reporting year start day attribute takes its semantic from its concept identity (usually the REPORTING_YEAR_START_DAY concept), yet is always has a fixed identifier (REPORTING_YEAR_START_DAY). The reporting year start day attribute always has a fixed text format, which specifies that the format of its value is always a day and month in the ISO 8601 format of '--MM-DD'. As with any other attribute, an attribute relationship must be specified. this relationship should be carefully selected as it will determin what type of data the data structure definition will allow. For example, if an attribute relationship of none is specified, this will mean the data sets conforming to this data structure definition can only contain data with standard reporting periods where the all reporting periods have the same start day. In this case, data reported as standard reporting periods from two entities with different fiscal year start days could not be contained in the same data set. + + + + + + + + + + + + + + + + + ReportingYearStartDayRepresentationType defines the representation for the reporting year start day attribute. Enumerated values are not allowed and the text format is fixed to be a day and month in the ISO 8601 format of '--MM-DD'. + + + + + + + + + + + + + ReportingYearStartDayTextFormatType is a restricted version of the NonFacetedTextFormatType that fixes the value of the text type to be DayMonth. This type exists solely for the purpose of fixing the representation of the reporting year start day attribute. + + + + + + + + + + + DimensionList describes the key descriptor for the data structure definition. It is an ordered set of metadata concepts that, combined, classify a statistical series, such as a time series, and whose values, when combined (the key) in an instance such as a data set, uniquely identify a specific series. + + + + + + + + + + DimensionListBaseType is an abstract base type used as the basis for the DimensionListType. + + + + + + + + + The id attribute is provided in this case for completeness. However, its value is fixed to DimensionDescriptor. + + + + + + + + + DimensionListType describes the key descriptor for a data structure definition. The order of the declaration of child dimensions is significant: it is used to describe the order in which they will appear in data formats for which key values are supplied in an ordered fashion (exclusive of the time dimension, which is not represented as a member of the ordered key). Any data structure definition which uses the time dimension should also declare a frequency dimension, conventionally the first dimension in the key (the set of ordered non-time dimensions). If is not necessary to assign a time dimension, as data can be organised in any fashion required. + + + + + + + + + + + + + + + BaseDimensionBaseType is an abstract base type that serves as the basis for any dimension. It restricts the text format base to a text format valid for data components (that does not allow for XHTML representation). + + + + + + + + + + + + + + + BaseDimensionType is an abstract base type which defines the basic structure of all dimensions. + + + + + + + ConceptRole references concepts which define roles which this dimension serves. If the concept from which the attribute takes its identity also defines a role the concept serves, then the isConceptRole indicator can be set to true on the concept identity rather than repeating the reference here. + + + + + + The position attribute specifies the position of the dimension in the data structure definition. It is optional an the position of the dimension in the key descriptor (DimensionList element) always takes precedence over the value supplied here. This is strictly for informational purposes only. + + + + + The type attribute identifies whether then dimension is a measure dimension, the time dimension, or a regular dimension. Although these are all apparent by the element names, this attribute allows for each dimension to be processed independent of its element as well as maintaining the restriction of only one measure and time dimension while still allowing dimension to occur in any order. + + + + + + + + + Dimension describes the structure of a dimension, which is defined as a statistical concept used (most probably together with other statistical concepts) to identify a statistical series, such as a time series, e.g. a statistical concept indicating certain economic activity or a geographical reference area. + + + + + + DimensionType describes the structure of an ordinary dimension, which is defined as a statistical concept used (most probably together with other statistical concepts) to identify a statistical series, such as a time series, e.g. a statistical concept indicating certain economic activity or a geographical reference area. The dimension takes its semantic, and in some cases it representation, from its concept identity. A dimension can be coded by referencing a code list from its coded local representation. It can also specify its text format, which is used as the representation of the dimension if a coded representation is not defined. Neither the coded or uncoded representation are necessary, since the dimension may take these from the referenced concept. + + + + + + + + + + + + + + + + + TimeDimension is a special dimension which designates the period in time in which the data identified by the full series key applies. + + + + + + TimeDimensionType describes the structure of a time dimension. The time dimension takes its semantic from its concept identity (usually the TIME_PERIOD concept), yet is always has a fixed identifier (TIME_PERIOD). The time dimension always has a fixed text format, which specifies that its format is always the in the value set of the observational time period (see com:ObservationalTimePeriodType). It is possible that the format may be a sub-set of the observational time period value set. For example, it is possible to state that the representation might always be a calendar year. See the enumerations of the textType attribute in the LocalRepresentation/TextFormat for more details of the possible sub-sets. It is also possible to facet this representation with start and end dates. The purpose of such facts is to restrict the value of the time dimension to occur within the specified range. If the time dimension is expected to allow for the standard reporting periods (see com:ReportingTimePeriodType) to be used, then it is strongly recommended that the reporting year start day attribute also be included in the data structure definition. When the reporting year start day attribute is used, any standard reporting period values will be assumed to be based on the start day contained in this attribute. If the reporting year start day attribute is not included and standard reporting periods are used, these values will be assumed to be based on a reporting year which begins January 1. + + + + + + + + + + + + + + + + + MeasureDimension is a special type of dimension which defines multiple measures in a key family. This is represented as any other dimension in a unless it is the observation dimension. It takes it representation from a concept scheme, and this scheme defines the measures and their representations. When data is formatted with this as the observation dimension, these measures can be made explicit or the value of the dimension can be treated as any other dimension. If the measures are explicit, the representation of the observation will be specific to the core representation for each concept in the representation concept scheme. Note that it is necessary that these representations are compliant (the same or derived from) with that of the primary measure. + + + + + + MeasureDimensionType defines the structure of the measure dimension. It is derived from the base dimension structure, but requires that a coded representation taken from a concept scheme is given. + + + + + + + + + + + + + + + + + Group describes a group descriptor in a data structure definition. It is a set metadata concepts (and possibly their values) that define a partial key derived from the key descriptor in a data structure definition. + + + + + + GroupBaseType is an abstract base type that forms the basis for the GroupType. + + + + + + + + + + + + + + GroupType describes the structure of a group descriptor in a data structure definition. A group may consist of a of partial key, or collection of distinct cube regions or key sets to which attributes may be attached. The purpose of a group is to specify attributes values which have the same value based on some common dimensionality. All groups declared in the data structure must be unique - that is, you may not have duplicate partial keys. All groups must be given unique identifiers. + + + + + + + + AttachmentConstraint references an attachment constraint that defines the key sets and/or cube regions that attributes may be attached to. This is an alternative to referencing the dimensions, and allows attributes to be attached to data for given values of dimensions. + + + + + + + + + + GroupDimension is a component which contains only a reference to a dimension in the key descriptor (DimensionList). Although it is conventional to declare dimensions in the same order as they are declared in the ordered key, there is no requirement to do so - the ordering of the values of the key are taken from the order in which the dimensions are declared. Note that the id of a dimension may be inherited from its underlying concept - therefore this reference value may actually be the id of the concept. + + + + + + GroupDimensionBaseType is an abstract base type which refines the base ComponentType in order to form the basis for the GroupDimensionType. + + + + + + + + + + + + + GroupDimensionType defines a dimension component with a group key descriptor component list. Although technically a component, this is essentially a reference to a dimension defined in the key descriptor. Therefore, the identification, name, and description, concept identity and representation properties that are typically available for a component are not allowed here, as they are all inherited from the referenced dimension. + + + + + + + DimensionReference provides a reference to a dimension defined in the key descriptor of the data structure definition in which this group key descriptor is defined. + + + + + + + + + + MeasureList describes the measure descriptor for a key family. It contains a single metadata concepts that define the primary measures of a data structure. + + + + + + MeasureListType describes the structure of the measure descriptor for a data structure definition. Only a primary may be defined. + + + + + + + + + + + + + + + PrimaryMeasure defines the structure of the primary measure, which is the concept that is the value of the phenomenon to be measured in a data set. Although this may take its semantic from any concept, this is provided a fixed identifier (OBS_VALUE) so that it may be easily distinguished in data messages. + + + + + + PrimaryMeasureType describes the structure of the primary measure. It describes the observation values for all presentations of the data. The primary measure takes its semantic, and in some cases it representation, from its concept identity (conventionally the OBS_VALUE concept). The primary measure can be coded by referencing a code list from its coded local representation. It can also specify its text format, which is used as the representation of the primary measure if a coded representation is not defined. Neither the coded or uncoded representation are necessary, since the primary measure may take these from the referenced concept. Note that if the data structure declares a measure dimension, the representation of this must be a superset of all possible measure concept representations. + + + + + + + + + + + + + + + + DataStructureRepresentationType is an abstract base type which defines the allowable representations for any data structure definition component. The enumeration must be restricted to the proper type for item scheme for a given component. + + + + + + + + + + + + + + + + + SimpleDataStructureRepresentationType defines the representation for any non-measure and non-time dimension data structure definition component. + + + + + + + + + + + + + + + + + BaseDimensionRepresentationType is an abstract base which defines the representation for a measure dimension. + + + + + + + + + + + + + TimeDimensionRepresentationType defines the representation for the time dimension. Enumerated values are not allowed. + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureDataflow.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureDataflow.xsd new file mode 100644 index 0000000..6dd3925 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureDataflow.xsd @@ -0,0 +1,32 @@ + + + + + + + + SDMX Dataflow Structure Module + The data flow structure module defines the structure of data flow constructs. + + + + + DataflowType describes the structure of a data flow. A data flow is defined as the structure of data that will provided for different reference periods. If this type is not referenced externally, then a reference to a key family definition must be provided. + + + + + + + + + + Structure provides a reference to the data structure definition which defines the structure of all data for this flow. + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureHierarchicalCodelist.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureHierarchicalCodelist.xsd new file mode 100644 index 0000000..c4e2a50 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureHierarchicalCodelist.xsd @@ -0,0 +1,267 @@ + + + + + + + + SDMX Hierarchical Code List Structure Module + The hierarchical code list structure module defines the structure of hierarchical code list constructs. + + + + + HierarchicalCodelistBaseType is an abstract base class that is the basis for the HierarchicalCodelistType. It requires that a name be supplied. + + + + + + + + + + + + + + + HierarchicalCodelistType describes the structure of a hierarchical codelist. A hierarchical code list is defined as an organised collection of codes that may participate in many parent/child relationships with other codes in the list, as defined by one or more hierarchy of the list. + + + + + + + IndludedCodelist provides a collection of references to the code lists whose codes are arranged in this hierarchical code list. + + + + + Hierarchy describes a classification structure arranged in levels of detail from the broadest to the most detailed level. These levels can be formal or informal, and are not necessary to describe. If the hierarchy does contain levels, then each hierarchical code is assumed to exist in the level where the depths of nesting match. + + + + + + + + + + + + + + + + + + HierarchyBaseType is an abstract base type that serves as the basis for the HierarchyType. It requires a name and id be provided. + + + + + + + + + + + + + + + + The Hierarchy is an abstract type that provides for a classification structure of referenced codes arranged in levels of detail from the broadest to the most detailed level. The levels in which the code exist can be formal or informal. + + + + + + + HierarchicalCode is used to assemble the codes from the codelist(s) referenced into a hierarchy. + + + + + + + + + In a formally leveled hierarchy, Level describes a group of codes which are characterised by homogeneous coding, and where the parent of each code in the group is at the same higher level of the hierarchy. In a value based hierarchy Level describes information about the codes at the specified nesting level. This structure is recursive to indicate the hierarchy of the levels. + + + + + + The leveled attribute indicates that the hierarchy has formal levels. In this case, every code should have a level associated with it. + + + + + + + + + HierarchicalCodeBaseType is an abstract base type the creates the basis for the HierarchicalCodeType. It removes the urn and uri. + + + + + + + + + The id attribute allows for an id to be assigned to the use of the particular code at that specific point in the hierarchy. This value is unique within the hierarchy being created, and is used to map the hierarchy against external structures. + + + + + + + + + HierarchicalCodeType describes the structure of a hierarchical code. A hierarchical code provides for a reference to a code that is referenced within the hierarchical code list via either a complete reference to a code through either a URN or full set of reference fields, or a local reference which utilizes the included codelist reference alias and the identification of a code from the list. Codes are arranged in a hierarchy by this reference. Note that it is possible to reference a single code such that it has multiple parents within the hierarchy. Further, the hierarchy may or may not be a leveled one. + + + + + + + + Code provides a complete, explicit reference to a code through either its URN, or a complete reference to the codelist and code. + + + + + + CodelistAliasRef references an alias assigned in a IncludedCodelistReference element in the containing hierarchical codelist. This is used in conjunction with the CodeID element to reference a code from one of the included codelists. + + + + + CodeID references the id of a code from the codelist that is referenced through the CodelistAliaRef element. + + + + + + + HierarchicalCode is used to nest referenced codes into a value based hierarchy. + + + + + + + + + Level references a formal level defined within the hierarchy which defines this hierarchical code. This is only necessary if the nesting depth of the hierarchical code does not correspond to the nesting depth of the level to which it belongs (i.e. the hieararchical code is to skip down a level). Otherwise, the code is assumed to exist at the level in which the nesting depth of the level matches the nesting depth of the code. + + + + + + The version attriubte contains a version number for the hierarchical code. A hierarchical code is not formally versionable, therefore each code must have a unique identifier. The version supplied here is for informational purposes only and is not used to uniquely identity the code. + + + + + The validFrom attriubte indicates the point in time in which the hiearchical code became effective. This can be used to track the historicity of codes changing over time. + + + + + The validTo attriubte indicates the point in time in which the hiearchical code became no longer effective. This can be used to track the historicity of codes changing over time. + + + + + + + + + LevelBaseType is an abstract base type that makes up the basis for the LevelType. It requires a name and id. + + + + + + + + + + + + + + + + LevelType describes a level in a hierarchical codelist. Where level is defined as a group where codes can be characterised by homogeneous coding, and where the parent of each code in the group is at the same higher level of the hierarchy. + + + + + + + CodingFormat specifies the text formatting of the codes in this level. This includes facets such as the expected characters and the length of the codes. + + + + + Level describes the next level down in the hierarchy. + + + + + + + + + + IncludedCodelistReferenceType provides the structure for a referencing a codelist and optionally providing a local alias identification for this reference. + + + + + + The alias attribute is used to carry the identifier for the referenced codelist, so that codes from that list can be easily referenced by the hierarchical codes contained in the parent hierarchy, without having to repeat the reference to the codelist itself. The alias attribute must be unique within the parent hierarchical codelist. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SimpleCodeDataType restricts SimpleDataType to specify the allowable data types for a simple code. The possible values are simply Alpha, AlphaNumeric, or Numeric. + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataStructure.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataStructure.xsd new file mode 100644 index 0000000..c1e45b9 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataStructure.xsd @@ -0,0 +1,500 @@ + + + + + + + + SDMX Metadata Structure Structure Module + The Metadata Structure structure module defines the structure of metadata structure definition constructs. + + + + + MetadataStructureType is used to describe a metadata structure definition, which is defined as a collection of metadata concepts, their structure and usage when used to collect or disseminate reference metadata. + + + + + + + + + + + + + + + + + + MetadataStructureComponents defines the grouping of the sets of the components that make up the metadata structure definition. All components and component list (target identifiers, identifier components, report structures, and metadata attributes) in the structure definition must have a unique identification. + + + + + + + + + + + + + + MetadataStructureComponentsBaseType is an abstract base type that forms the basis for the MetadataStructureComponentsType. + + + + + + + + + MetadataStructureComponentsType describes the structure of the grouping of the sets of the components that make up the metadata structure definition. At a minimum, a full target identifier and at least one report structure must be defined. + + + + + + + + + + + + + + MetadataTarget is a collection of target objects which when taken together describe a structure which defines the key of an object type to which metadata may be attached and serve to disambiguate reference metadata set reports. + + + + + + + + + + MetadataTargetBaseType is an abstract base type which forms the basis for the MetadataTargetType. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TargetObject is an abstract base type from which all target objects of a metadata target are derived. It is based on a component. Implementations of this will refined the local representation so that the allowed values accurately reflect the representation of the target object reference. + + + + + + + + + KeyDescriptorValuesTarget is target object which references a data key for the purpose of attach reference metadata to portions of data. A data key is a set of dimension references and values for those dimension. This component on its own is not of much use, as the data key only has local references to the dimensions. Therefore it is typical that this is used in combination with some sort of reference to the data (either a data set reference or a reference to the underlying structure, structure usage, or provision agreement of the data. + + + + + + KeyDescriptorValuesTargetType defines the structure of a key descriptor values target object. The key descriptor values target object has a fixed representation and identifier. + + + + + + + + + + + + + + + DataSetTarget is target object which references a data set for the purpose of attaching reference metadata data. A data set reference is a full reference to a data provider and an identifier for the data set. + + + + + + DataSetTargetType defines the structure of a data set target object. The data set target object has a fixed representation and identifier. + + + + + + + + + + + + + + + ConstraintContentTarget is target object which references an attachment constraint for the purpose of attaching reference metadata data to data key sets or cube regions defined by the constraint. + + + + + + ConstraintTargetType defines the structure of a constraint target object. The constraint target object has a fixed representation and identifier. + + + + + + + + + + + + + + + ReportPeriodTarget is target object which specifies a reporting period to which a metadata report applies. + + + + + + ReportPeriodTargetType defines the structure of a report period target object. The report period target object has a fixed representation and identifier. + + + + + + + + + + + + + + + IdentifiableObjectTarget is target object which references an Identifiable object as defined in the SDMX Information Model. The reference must be complete (i.e. a URN or a complete set of reference fields). For an item object, it is possible to define a local representation of an item scheme from which the item must be referenced. + + + + + + IdentifiableObjectTargetBaseType is an abstract base type which forms the basis for the IdentifiableObjectTargetType. + + + + + + + + + + + + + + + IdentifiableObjectTargetType defines the structure of an identifiable target object. The identifiable target object has a fixed representation of a reference and can specify a local representation of any item scheme for the purpose of restricting which items may be referenced. The identifiable object target must specify the object type which the target object is meant to reference. + + + + + + + + + + + ReportStructure defines a report structure, which comprises a set of metadata attributes that can be defined as a hierarchy, for reporting reference metadata about a target object. The identification of metadata attributes must be unique at any given level of the report structure. Although there are XML schema constraints to help enforce this, these only apply to explicitly assigned identifiers. Identifiers inherited from a concept from which a metadata attribute takes its identity cannot be validated against this constraint. Therefore, systems processing metadata structure definitions will have to perform this check outside of the XML validation. + + + + + + + + + + ReportStructureBaseType is an abstract base type that serves as the basis for the ReportStructureType. + + + + + + + + + + + + + + + + + ReportStructureType describes the structure of a report structure. It comprises a set of metadata attributes that can be defined as a hierarchy, and identifies the potential attachment of these attributes to an object by referencing a target identifier. + + + + + + + MetadataTarget references a metadata target defined in the metadata structure definition. A report structure can reference multiple metadata targets which allows a report structure to be reused for attaching metadata to different types of targets. + + + + + + + + + + MetadataAttribute defines the a metadata attribute, which is the value of an attribute, such as the instance of a coded or uncoded attribute in a metadata structure definition. + + + + + + + + + + MetadataAttributeBaseType is an abstract base type the serves as the basis for the MetadataAttributeType. + + + + + + + + + + + + + + + MetadataAttributeType describes the structure of a metadata attribute. The metadata attribute takes its semantic, and in some cases it representation, from its concept identity. A metadata attribute may be coded (via the local representation), uncoded (via the text format), or take no value. In addition to this value, the metadata attribute may also specify subordinate metadata attributes. If a metadata attribute only serves the purpose of containing subordinate metadata attributes, then the isPresentational attribute should be used. Otherwise, it is assumed to also take a value. If the metadata attribute does take a value, and a representation is not defined, it will be inherited from the concept it takes its semantic from. The optional id on the metadata attribute uniquely identifies it within the metadata structured definition. If this id is not supplied, its value is assumed to be that of the concept referenced from the concept identity. Note that a metadata attribute (as identified by the id attribute) definition must be unique across the entire metadata structure definition (including target identifier, identifier component, and report structure ids). A metadata attribute may be used in multiple report structures and at different levels, but the content (value and/or child metadata attributes and their cardinality) of the metadata attribute cannot change. + + + + + + + + + The minOccurs attribute indicates the minimum number of times this metadata attribute can occur within its parent object. + + + + + The maxOccurs attribute indicates the maximum number of times this metadata attribute can occur within its parent object. + + + + + The isPresentational attribute indicates whether the metadata attribute should allow for a value. A value of true, meaning the metadata attribute is presentational means that the attribute only contains child metadata attributes, and does not contain a value. If this attribute is not set to true, and a representation (coded or uncoded) is not defined, then the representation of the metadata attribute will be inherited from the concept from which it takes its identity. + + + + + + + + + KeyDescriptorValuesRepresentationType defines the possible local representations of a key descriptor values target object. The representation is fixed to always be a data key (KeyValues). + + + + + + + + + + + + + DataSetRepresentationType defines the possible local representations of a data set reference target object. The representation is fixed to always be a data set reference. + + + + + + + + + + + + + ConstraintRepresentationType defines the possible local representations of a constraint reference target object. The representation is fixed to always be an attachment constraint reference. + + + + + + + + + + + + + ReportPeriodRepresentationType defines the possible local representations of a report period target object. The reprentation must be a time period or a subset of this representation. + + + + + + + + + + + + + IdentifiableObjectRepresentationType defines the possible local representations of an identifiable object target object. + + + + + + + + + Enumeration is only permissible if the object type of the identifiable object target is an item in an item scheme. This enumeration is meant to limit the referencable objects to the items defined in the referenced item scheme. + + + + + + + + + + + MetadataAttributeRepresentationType defines the possible local representations of a metadata attribute. + + + + + + + + + + + + + + + + + TargetObjectTextFormatType is a restricted version of the TextFormatType that does not allow for any facets and only allows the text types for target objects. + + + + + + + + + + + + + + + + + + + + + + + + + TargetObjectDataType restricts DataType to specify the allowable data types for representing a target object value. + + + + + + + + + + + + KeyDescriptorValuesTextFormatType is a restricted version of the NonFacetedTextFormatType that specifies a fixed KeyValues representation. + + + + + + + + + + + DataSetTextFormatType is a restricted version of the NonFacetedTextFormatType that specifies a fixed DataSetReference representation. + + + + + + + + + + + ConstraintTextFormatType is a restricted version of the NonFacetedTextFormatType that specifies a fixed AttachmentConstraintReference representation. + + + + + + + + + + + IdentifiableObjectTextFormatType is a restricted version of the NonFacetedTextFormatType that specifies a fixed IdentifiableReference representation. + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataflow.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataflow.xsd new file mode 100644 index 0000000..7aedc42 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataflow.xsd @@ -0,0 +1,32 @@ + + + + + + + + SDMX Metadataflow Structure Module + The metadata flow structure module defines the structure of metadata flow constructs. + + + + + MetadataflowType describes the structure of a metadata flow. A dataflow is defined as the structure of reference metadata that will be provided for different reference periods. If this type is not referenced externally, then a reference to a metadata structure definition must be provided + + + + + + + + + + Structure provides a reference to the metadata structure definition describing the structure of all reference metadata for this flow. + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureOrganisation.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureOrganisation.xsd new file mode 100644 index 0000000..3b78ee1 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureOrganisation.xsd @@ -0,0 +1,313 @@ + + + + + + + + SDMX Organisation Structure Module + The organisation structure module defines the structure of organisation schemes and organisation constructs. + + + + + OrganisationSchemeBaseType is an abstract base type for any organisation scheme. + + + + + + + + + + + + + + + OrganisationSchemeType describes the structure of an organisation scheme. + + + + + + + + + + + + + Organisation is an abstract substitution head for a generic organisation. + + + + + + BaseOrganisationType is an abstract base type the forms the basis for the OrganisationType. + + + + + + + + + + + If the particular organisation scheme allows, an organisation may reference a parent organisation defined in the same scheme. This does not affect the identification of the organisation, but rather only serves to state the relationship. + + + + + + + + + + + OrganisationType in an abstract type which describes the structure of the details of an organisation. In addition to the basic organisation identification, contact details can be provided. + + + + + + + Contact describes a contact for the organisation, + + + + + + + + + + AgencySchemeType defines a specific type of organisation scheme which contains only maintenance agencies. The agency scheme maintained by a particular maintenance agency is always provided a fixed identifier and version, and is never final. Therefore, agencies can be added or removed without have to version the scheme. Agencies schemes have no hierarchy, meaning that no agency may define a relationship with another agency in the scheme. In fact, the actual parent agency for an agency in a scheme is the agency which defines the scheme. + + + + + + + + + + + + + + + + + + + + + DataConsumerSchemeType defines a type of organisation scheme which contains only data consumers. The data consumer scheme maintained by a particular maintenance agency is always provided a fixed identifier and version, and is never final. Therefore, consumers can be added or removed without have to version the scheme. This scheme has no hierarchy, meaning that no organisation may define a relationship with another organisation in the scheme. + + + + + + + + + + + + + + + + + + + + + DataProviderSchemeType defines a type of organisation scheme which contains only data providers. The data provider scheme maintained by a particular maintenance agency is always provided a fixed identifier and version, and is never final. Therefore, providers can be added or removed without have to version the scheme. This scheme has no hierarchy, meaning that no organisation may define a relationship with another organisation in the scheme + + + + + + + + + + + + + + + + + + + + + OrganisationUnitSchemeType defines a type of organisation scheme which simply defines organisations and there parent child relationships. Organisations in this scheme are assigned no particular role, and may in fact exist within the other type of organisation schemes as well. + + + + + + + + + + + + + + + + + + Agency is an organisation which maintains structural metadata such as statistical classifications, glossaries, key family structural definitions, and metadata structure definitions.. + + + + + + DataConsumer describes an organisation using data as input for further processing. + + + + + + DataProvider describes an organisation that produces data or reference metadata. + + + + + + OrganisationUnit describes a generic organisation, which serves not predefined role in SDMX. + + + + + + AgencyType defines the structure of an agency description. The contacts defined for the organisation are specific to the agency role the organisation is serving. + + + + + + + + + + + + The id attribute holds the identification of the agency. The type of this id is restricted to the com:NCNNameIDType. This is necessary, since the agency identifier will be used as part of the name for simple types in data and metadata structure specific schemas and therefore must be compliant with the NCName type in XML Schema (see com:NCNameIDType for further details). + + + + + + + + + DataConsumerType defines the structure of a data consumer description. The contacts defined for the organisation are specific to the data consumer role the organisation is serving. + + + + + + + + + + + + + + + + DataProviderType defines the structure of a data provider description. The contacts defined for the organisation are specific to the data provider role the organisation is serving. + + + + + + + + + + + + + + + + OrganisationUnitType defines the structure of an organisation unit description. In addition to general identification and contact information, an organisation unit can specify a relationship with another organisation unit from the same scheme which is its parent organisation. + + + + + + + + + + + + + + + + + + + ContactType describes the structure of a contact's details. + + + + + + Department is designation of the organisational structure by a linguistic expression, within which the contact person works. + + + + + Role is the responsibility of the contact person with respect to the object for which this person is the contact. + + + + + + Telephone holds the telephone number for the contact person. + + + + + Fax holds the fax number for the contact person. + + + + + X400 holds the X.400 address for the contact person. + + + + + URI holds an information URL for the contact person. + + + + + Email holds the email address for the contact person. + + + + + + + The id attribute is used to carry user id information for the contact. + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureProcess.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureProcess.xsd new file mode 100644 index 0000000..86c3bd3 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureProcess.xsd @@ -0,0 +1,176 @@ + + + + + + + + SDMX Process Structure Module + The process structure module defines the structure of process and process step constructs. + + + + + ProcessType describes the structure of a process, which is a scheme which defines or documents the operations performed on data in order to validate data or to derive new information according to a given set of rules. Processes occur in order, and will continue in order unless a transition dictates another step should occur. + + + + + + + ProcessStep defines a process step, which is a specific operation, performed on data in order to validate or to derive new information according to a given set of rules. + + + + + + + + + + + + + + ProcessStepBaseType is an abstract base type used as the basis for the ProcessStepType. + + + + + + + + + + + + + + + + ProcessStepType describes the structure of a process step. A nested process step is automatically sub-ordinate, and followed as the next step. If the following step is conditional, it should be referenced in a transition. + + + + + + + Input references an object which is an input to the process step. + + + + + Output references an object which is an output form the process step. + + + + + Computation describes the computations involved in the process, in any form desired by the user (these are informational rather than machine-actionable), and so may be supplied in multiple, parallel-language versions. + + + + + Transition describes the next process steps. Each transition in a process step should be evaluated, allowing for multiple process step branches from a single process step. + + + + + ProcessStep defines a process step, which is a specific operation, performed on data in order to validate or to derive new information according to a given set of rules. + + + + + + + + + + + + + + TransitionType describes the details of a transition, which is an expression in a textual or formalised way of the transformation of data between two specific operations performed on the data. + + + + + + + TargetStep references a process step within the process that should be transitioned to, should the conditions described be met. + + + + + Condition is a textual description of the conditions to be met in order for the target step to be proceeded to. It is informational only (not machine-actionable), and may be supplied in multiple, parallel-language form. + + + + + + The localID attribute is an optional identification for the transition within the process. + + + + + + + + + ComputationType describes a computation in a process. + + + + + + + Description describe the computation in any form desired by the user (these are informational rather than machine-actionable), and so may be supplied in multiple, parallel-language versions, + + + + + + The localID attribute is an optional identification for the computation within the process. + + + + + The softwarePackage attribute holds the name of the software package that is used to perform the computation. + + + + + The softwareLanguage attribute holds the coding language that the software package used to perform the computation is written in. + + + + + The softwareVersion attribute hold the version of the software package that is used to perform that computation. + + + + + + + + + InputOutputType describes the structure of an input or output to a process step. It provides a reference to the object that is the input or output. + + + + + + + ObjectReference is an abstract substitution head that references the object that is an input or output. It is substituted with a concrete reference to an explicit object type. + + + + + + The localID attribute is an optional identification for the input or output within the process. + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureProvisionAgreement.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureProvisionAgreement.xsd new file mode 100644 index 0000000..3d7fe84 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureProvisionAgreement.xsd @@ -0,0 +1,34 @@ + + + + + + + + SDMX Provision Agreement Module + The provision agreement module defines the structure of the provision agreement constructs. + + + + + ProvisionAgreementType describes the structure of a provision agreement. A provision agreement defines an agreement for a data provider to report data or reference metadata against a flow. Attributes which describe how the registry must behave when data or metadata is registered against this provision agreement are supplied. + + + + + + + DataflowReference provides a reference to a pre-existing structure usage (i.e. a dataflow or metadataflow) in the registry. The reference is provided via a URN and/or a full set of reference fields. + + + + + DataProvider provides a reference to a pre-existing data (or metadata) provider in the registry. The reference is provided via a URN and/or a full set of reference fields. + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureReportingTaxonomy.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureReportingTaxonomy.xsd new file mode 100644 index 0000000..b2e8933 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureReportingTaxonomy.xsd @@ -0,0 +1,83 @@ + + + + + + + + SDMX Reporting Taxonomy Structure Module + The reporting taxonomy structure module defines the structure of reporting taxonomy and reporting category constructs. + + + + + ReportingTaxonomyType describes the structure of a reporting taxonomy, which is a scheme which defines the composition structure of a data report where each component can be described by an independent structure or structure usage description. + + + + + + + + + + + + + + + + + + ReportingCateogry defines a reporting category, which is used to group structure usages into useful sub-packages. + + + + + + + + + + ReportingCategoryBaseType is an abstract base type that serves as the basis for the ReportingCategoryType. + + + + + + + + + + + + + + + + + + + + ReportingCategoryType describes the structure of a reporting category, which groups structure usages into useful sub-packages. Sub ordinate reporting categories can be nested within the category definition. + + + + + + + StructuralMetadata provides a reference for data structure definition and metadata structure definition references which are grouped in the reporting category. It is assumed that all structural metadata objects referenced from a category will be of the same type. + + + + + ProvisioningMetadata provides a reference for dataflow and metadataflow references which are grouped in the reporting category. It is assumed that all provisioning metadata objects referenced from a category will be of the same type. + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureStructureSet.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureStructureSet.xsd new file mode 100644 index 0000000..82d5c30 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureStructureSet.xsd @@ -0,0 +1,561 @@ + + + + + + + + SDMX Structure Set Structure Module + The structure set structure module defines the structure of structure set and structure map constructs. + + + + + StructureSetBaseType is an abstract base type that forms the basis for the StructureSetType. + + + + + + + + + + + + + + + StructureSetType describes the structure of a structure set. It allows components in one structure, structure usage, or item scheme to be mapped to components in another structural component of the same type. + + + + + + + RelatedStructures contains references to structures (key families and metadata structure definitions) and structure usages (data flows and metadata flows) to indicate that a semantic relationship exist between them. The details of these relationships can be found in the structure maps. + + + + + + OrganisationSchemeMap links a source and target organisations from different schemes where there is a semantic equivalence between them. Organisations are mapped without regard to role. + + + + + CategorySchemeMap links a source and target categories from different schemes where there is a semantic equivalence between them. + + + + + CodelistMap links a source and target codes from different lists where there is a semantic equivalence between them. + + + + + ConceptSchemeMap links a source and target concepts from different schemes where there is a semantic equivalence between them. + + + + + ReportingTaxonomyMap links a source and target reporting categories from different taxonomies where there is a semantic equivalence between them. + + + + + HybridCodelistMap links a source and target codes from different codelists, which may be hierarchical or flat, where there is a semantic equivalence between them. + + + + + StructureMap maps components from one structure to components to another structure, and can describe how the value of the components are related. + + + + + + + + + + + ItemSchemeMapBaseType is an abstract base type which forms the basis for the ItemSchemeMapType. + + + + + + + + + + + + + + + + ItemSchemeMapType is an abstract base type which forms the basis for mapping items between item schemes of the same type. + + + + + + + Source provides a reference to the item scheme which items are mapped from. + + + + + Target provides a reference to the item scheme which items are mapped to. + + + + + + + + + + + + + ItemAssociation is an abstract description of the relation between two items for the purpose of mapping. + + + + + + ItemAssociationType is an abstract type which defines the relationship between two items from the source and target item schemes of an item scheme map. + + + + + + + Source provides a local reference (id only) to an item from the source item scheme in the item scheme map which is being mapped to another item. + + + + + Target provides a local reference (id only) to an item from the target item scheme in the item scheme map which is being mapped from another item. + + + + + + + + + + OrganisationSchemeMapType defines the structure of a map which identifies relationships between organisations in different organisation schemes. + + + + + + + + + + + + + + + + + + + + OrganisationMap relates a source organisation to a target organisation. + + + + + + OrganisationMapType defines the structure for mapping two organisations. A local reference is provided both the source and target organisation. + + + + + + + + + + + + + + + CategorySchemeMapType defines the structure of a map which identifies relationships between categories in different category schemes. + + + + + + + + + + + + + + + + + + + + CategoryMap defines the structure of a map which identifies relationships between categories in different category schemes. + + + + + + CategoryMapType defines the structure for mapping two categories. A local reference is provided both the source and target category. + + + + + + + + + + + + + + + CodelistMapType defines the structure of a map which identifies relationships between codes in different codelists. + + + + + + + + + + + + + + + + + + + + CodeMap defines the structure of a map which identifies relationships between codes in different codelists. + + + + + + CodeMapType defines the structure for mapping two codes. A local reference is provided both the source and target code. + + + + + + + + + + + + + + + ConceptSchemeMapType defines the structure of a map which identifies relationships between concepts in different concept schemes. + + + + + + + + + + + + + + + + + + + + ConceptMap defines the structure of a map which identifies relationships between concepts in different concept schemes. + + + + + + ConceptMapType defines the structure for mapping two concepts. A local reference is provided both the source and target concept. + + + + + + + + + + + + + + + ReportingTaxonomyMapType defines the structure of a map which identifies relationships between reporting categories in different reporting taxonomies. + + + + + + + + + + + + + + + + + + + + ReportingCategoryMap defines the structure of a map which identifies relationships between reporting categories in different reporting taxonomies. + + + + + + ReportingCategoryMapType defines the structure for mapping two reporting categories. A local reference is provided both the source and target category. + + + + + + + + + + + + + + + HybridCodelistMapBaseType is an abstract base type which forms the basis for the HybridCodelistMapType. + + + + + + + + + + + + + + + + HybridCodelistMapType defines the structure of a map which relates codes (possibly hierarchical) from different code lists. + + + + + + + Source provides a reference to either a codelist or a hierarchical codelist, from which the codes are to be mapped. + + + + + Target provides a reference to either a codelist or a hierarchical codelist, to which the source codes are to be mapped. + + + + + HybridCodeMap defines the relationship of a code in the source list to code in the target list. + + + + + + + + + + CodeMapType defines the structure for associating a code from a source codelist to a code in a target codelist. Note that either of these may come from a hierarchical codelist. + + + + + + + Source provides a local reference to the code which is to be mapped. If this code is from a hierarchical codelist, a reference to the hierarchy in which it is defined must also be provided. + + + + + Target provides a local reference to the code to which the source code is mapped. If this code is from a hierarchical codelist, a reference to the hierarchy in which it is defined must also be provided. + + + + + + + + + + StructureMapBaseType is an abstract base type which forms the basis for the StructureMapType. + + + + + + + + + + + + + + + + StructureMapType defines the structure for mapping components of one structure to components of another structure. A structure may be referenced directly meaning the map applies wherever the structure is used, or it may be a reference via a structure usage meaning the map only applies within the context of that usage. Using the related structures, one can make extrapolations between maps. For example, if key families, A, B, and C, are all grouped in a related structures container, then a map from key family A to C and a map from key family B to C could be used to infer a relation between key family A to C. + + + + + + + Source provides a reference to a structure (data or metadata) or a structure usage (dataflow or metadataflow) from which components defined by the actual structure are to mapped. + + + + + Target provides a reference to a structure (data or metadata) or a structure usage (dataflow or metadataflow) to which components from the source are to mapped. + + + + + ComponentMap defines the relationship between the components of the source and target structures, including information on how the value from the source component relates to values in the target component. + + + + + + The isExtension attribute, when true, indicates that the target structure definition inherits all properties of the referenced structure definition, and may have additional components. Note that this attribute may only be set to true if the structure map has a source structure and a target structure of either two key families or two metadata structure definitions. It is not possible inherit the underlying concepts of components between the two type of structures using this mechanism. + + + + + + + + + ComponentMapType defines the structure for relating a component in a source structure to a component in a target structure. + + + + + + + + + RepresentationMapping describes the mapping rules to map the value of the source component to the target component. Note that is a representation mapping is not supplied, then the value of the source component is mapped directly to the value of the target component without any manipulation. + + + + + + + + + + RepresentationMapType describes the structure of the mapping of the value of a source to component to a target component. Either a reference to another map defined within the containing structure set or a description of the source and target text formats must be provided. Note that for key family components, only a reference to a codelist map is relevant, since that is the only type of coded representation allowed in a key family. + + + + + CodelistMap references a codelist map defined in the same structure set which maps the enumeration of the representation of the source component to the enumeration of the representation of the target component. + + + + + + ToTextFormat describes the un-coded representation of the target to which the value of the referenced component should be transformed. + + + + + ToValueType notes whether the value, name, or description of the source value should be used in the target value. + + + + + + ValueMap provides for a simple mapping of a source value to a target value without having to define a codelist map. This is available to allow mappings in situations such as the source or target is not being formally coded, or the source and/or target being a measure dimension in which case its representation is not mappable from a codelist map. + + + + + + + + ValueMapType contains a collection of value mappings, which give a source and target value. + + + + + ValueMapping provides a source and target value for the purpose of mapping. + + + + + + + + ValueMappingType specifies the relationship between two values as a source and target. + + + + + + + + ToValueTypeType provides an enumeration of available text-equivalents for translation of coded values into textual formats. + + + + + Code or other tokenized value, as provided in the representation scheme. + + + + + The human-readable name of the Value, as provided in the representation scheme. + + + + + The human-readable description of the Value, as provided in the representation scheme. + + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureTransformation.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureTransformation.xsd new file mode 100644 index 0000000..c26161f --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/SDMXStructureTransformation.xsd @@ -0,0 +1,561 @@ + + + + + + + + SDMX Transformation Structure Module + The transformation structure module defines the structure of transformation scheme and transformation constructs. + + + + + VtlDefinitionSchemeType is an abstract extension of the ItemSchemeType for VTL schemes. + + + + + + Identifies the VTL version to which the items in the defined scheme comply. Note that definition schemes can only reference definition schemes using the same VTL version. + + + + + + + + + TransformationSchemeBaseType is an abstract base type for the TransformationSchemeType. It restricts the item types to be only transformations. + + + + + + + + + + + + + + + + + + TransformationSchemeType describes the structure of a transformation scheme. A transformation scheme contains a set of transformations to be executed together (in the same run). It can contain any number of transformations that produce any number of results. + + + + + + + References a VTL mapping scheme which defines aliases for given SDMX artefacts that are used in the transformations as well as the mapping methods used when converting between SDMX and VTL data structures. All aliases must be defined in the referenced scheme. This also must be used if the basic mapping methods are not used. + + + + + References a name personalisation scheme, which defines the overriding of some standard VTL names (to be assigned to some measures and/or attributes of the data structure) with some corresponding personalised names. This must be used if transformations within a transformation scheme personalise standard names. All personalisations must be defined in the referenced scheme. + + + + + References a custom type scheme which defines custom conversions of VTL scalar types to SDMX data types. This must be used if custom type conversions are used in the transformations defined in a transformation scheme. All custom conversions must be defined in the referenced scheme. + + + + + References a ruleset scheme that defines one or more previously defined rulesets which can be invoked by VTL operators. If a transformation defined in a transformation scheme refers to a ruleset, the scheme in which the ruleset is defined must be referenced here. + + + + + References a user defined operator scheme that defines one or more user defined operators used by the transformations defined in a transformation scheme. If a transformation in a transformation scheme refers to a user defined operator, the scheme in which the user defined operator is defined must be referenced here. + + + + + + + + + + Transformation describes the details of a single transformation within a transformation scheme. + + + + + + TransformationType defines the structure of a transformation. A transformation is an assignment of a VTL expression to a specific result. + + + + + + + The right-hand side of the VTL statement. This is expression that is executed for this transformation. It include references to operands and other artefacts. The expression may contain references to SDMX artefacts using the reduced URN format; see Section 6 SDMX Standards ("SDMX Technical Notes"), 10.2.3 ("Abbreviation of the URN"). + + + + + The left-hand side of the VTL statement. This identifies the result artefact, which may be used in subsequent transformations. If the result is an SDMX artefact, the is expressed using the alias; see Section 6 SDMX Standards ("SDMX Technical Notes"), 10.2.3 ("Abbreviation of the URN"). + + + + + + Indicates if the the result is permanently stored. A persistent result (value of true) can be used by transformation defined in other transformation schemes, but a non-persistent result (value of false) can only be used by transformations within the same transformation scheme. + + + + + + + + + VtlMappingSchemeType defines a set of mappings between SDMX and VTL. + + + + + + + + + + + + + + + + + + VtlMapping details a mapping between SDMX and VTL transformation. + + + + + + VtlMappingType defines the structure of a single mapping between the reference to a SDMX artefact made from VTL transformations, rulesets, user defined operators and the corresponding SDMX structure identifier. These are used to assign an alternative names to SDMX Dataflows, Codelists, Concept Schemes, or Concepts. Although are distinct sub-classes in the Information Model, this structure serves to express them all. The references SDMX artefact serves to distinguish which type of sub-class (VtlDatflowMapping, VtlCodelistMapping, or VtlConceptSchemeMapping) is being described. When this is used to assign an alias for a SDMX Dataflow, this can also be used to indicate the methods used to convert the data structure from SDMX to VTL and vice-versa. Finally, this can be used to override the deault Basic mapping methods used for Dataflows by utilizing the GenericDataflow element in place of a reference to a specific Dataflow. + + + + + + + + + + A reference to the SDMX Dataflow that the mapping is defined for. This is used to create a VtlDataflowMapping. In this case, it is possible to specify the mapping details to and from VTL. + + + + + Indicates that the ToVtlMapping and FromVtlMapping are the default mapping methods to be applied, overriding the Basic methods if necessary. The mapping methods in this case would be applied to any dataflows that are not explicitly defined in other VtlMappings. + + + + + + Describes the mapping from a SDMX dataflow to a VTL data structure. + + + + + Describes the mapping to a SDMX dataflow from a VTL data structure. + + + + + + A reference to the SDMX Codelist that the mapping is defined for. This is used to create a VtlCodelistMapping. + + + + + A reference to the SDMX Concept Scheme that the mapping is defined for. This is used to create a VtlConceptSchemeMapping. + + + + + A reference to the SDMX Concept that the mapping is defined for. This is used to create a VtlConceptMapping. + + + + + + + The alias used to refer to the reference SDMX artefact in the transformations. This must be unique within the mapping scheme in which it is defined. + + + + + + + + + ToVtlMappingType defines the mapping method and filter used when mapping from SDMX to VTL. + + + + + Identfies a sub space of the mapped dataflow that the mapping applies to. This is a collection of references to the dimensions that make up the space. + + + + + + The mapping method used when mapping from SDMX to VTL. This is typically a StandardToVtlMappingMethodType, but can be any other value to allow for non-standard methods. The implied default is Basic. + + + + + + + A simple type enumerating the standard mapping methods when converting from data structures from SDMX to VLT. + + + + + The default mapping method. See Section 6 SDMX Standards ("SDMX Technical Notes"), 10.3.3.1 ("Basic Mapping"). + + + + + Method for mapping multi-measure data. See Section 6 SDMX Standards ("SDMX Technical Notes"), 10.3.3.2 ("Pivot Mapping"). + + + + + The basic mapping method, using attributes to measures. See Section 6 SDMX Standards ("SDMX Technical Notes"), 10.3.3.3 ("From SDMX DataAttributes to VTL Measures"). + + + + + The pivot mapping method, using attributes to measures. See Section 6 SDMX Standards ("SDMX Technical Notes"), 10.3.3.3 ("From SDMX DataAttributes to VTL Measures"). + + + + + + + + A simple type that allows for a standard to VTL mapping method enumeration value or a string value for other mapping methods. + + + + + + + FromVtlMappingType defines the mapping method and filter used when mapping from VTL to SDMX. + + + + + Identfies a super space of the mapped dataflow that the mapping applies to. This is a collection of references to the dimensions that make up the space. + + + + + + The mapping method used when mapping from VTL to SDMX. This is typically a StandardFromVtlMappingMethodType, but can be any other value to allow for non-standard methods. The implied default is Basic for single-measure VTL data structures and Unpivot for multi-meausre VTL data structures. + + + + + + + A simple type enumerating the standard mapping methods when converting from data structures from VTL to SDMX. + + + + + The default mapping method, applicable only when the VLT data structure has just one measure component. See Section 6 SDMX Standards ("SDMX Technical Notes"), 10.3.4.1 ("Basic Mapping"). + + + + + The mapping method to be used when the VTL data structure has more than one measure component. See Section 6 SDMX Standards ("SDMX Technical Notes"), 10.3.4.2 ("Unpivot Mapping"). + + + + + Mapping of multi-measure VTL where on measure is mapped to the SDMX primary measure and the remaining measures are mapped as data attributes. See Section 6 SDMX Standards ("SDMX Technical Notes"), 10.3.4.3 ("From VTL Measures to SDMX DataAttributes"). + + + + + + + + A simple type that allows for standard from VTL mapping method enumeration value or a string value for other mapping methods. + + + + + + + SpaceKey defines the structure of a super- or sub- space for a SDMX Dataflow. It is a collection of references to the dimensions that make up the space. + + + + + A reference to a dimension by its identifier. + + + + + + + + NamePersonalisationSchemeType defines a set of personalisations of VTL standard names that are used in a set of transformations. + + + + + + + + + + + + + + + + + + NamePersonalisation details a name personalisation that is used in a transformation. + + + + + + NamePersonalisationType defines the structure of a name personalisation. A name personalisation is is used in place of a standard VTL name in some VTL operations. + + + + + + + Provides the VTL standard name that is being personalised. + + + + + Provides the personalised name that is used in place of the VTL standard name in the transformation expressions. + + + + + + Identifies the type of VTL model artefact that is being personalised. In VTL 2.0, this is valuedomain or variable. + + + + + + + + + RulesetSchemeBaseType is an abstract base type for the RulesetSchemeType. It restricts the item types to be only rulesets. + + + + + + + + + + + + + + + + + + RulesetSchemeType defines a collection of rulesets that are used in transformations. + + + + + + + References a VTL mapping scheme which defines aliases for given SDMX artefacts that are used in the rulesets. Rulesets defined on value domains reference Codelists or Concept Schemes (the latter in VTL are considered as the Value Domains of the variables corresponding to the SDMX Measure Dimensions). The rulesets defined on variables reference Concepts (for which a definite representation is assumed). Therefore, a ruleset should only refer to Codelists, Concept Schemes, and Concepts. + + + + + + + + + + Ruleset details a ruleset within a ruleset scheme. + + + + + + RulesetType defines the structure of a ruleset. A ruleset is a persistent set of rules which can be invoked by using appropriate VTL operators. + + + + + + + A VTL statement for the definition of a ruleset. This must conform to the syntax of the VTL definition language. + + + + + + The VTL type of the ruleset. In VTL 2.0, this is datapoint or hierarchical + + + + + This model artefact on which the ruleset is defined. In VTL 2.0, this is value domain or variable. + + + + + + + + + UserDefinedOperatorSchemeBaseType is an abstract base type for the UserDefinedOperatorSchemeType. It restricts the item types to be only user defined operators. + + + + + + + + + + + + + + + + + + UserDefinedOperatorSchemeType defines a collection of user defined operators that are used in transformations. + + + + + + + References a VTL mapping scheme which defines aliases for given SDMX artefacts that are used in the user defined operators. Although the VTL user defined operators are conceived to be defined on generic operands, so that the specific artefacts to be manipulated are passed as parameters at the invocation, it is also possible that they reference specific SDMX artefacts like Dataflows, Codelists and ConceptSchemes. In this case, the mapping schemes referenced here define the mappings to those artefacts. + + + + + References a ruleset scheme defining rulesets utilized in the user defined operators. + + + + + + + + + + UserDefinedOperator details a user defined operators within a user defined operator scheme. + + + + + + UserDefinedOperatorType defines the structure of a user defined operator. A user defined operator is a custom VTL operator (not existing in the standard library) that extends the VTL standard library for specific purposes. In addition to its identification and name, and definition of the operator must be provided. + + + + + + + A VTL statement for the definition of a new operator: it specifies the operator name, its parameters and their data types, the VTL expression that defines its behaviour. + + + + + + + + + + CustomTypeSchemeType defines a collection of custom types that are used in transformations. + + + + + + + + + + + + + + + + + + CustomType details a custom type within a custom type scheme. + + + + + + CustomTypeType defines the structure of a custom type. A custom type specifies a custom conversion for a VTL scalar type to a resulting data type. This conversion overrides the default conversion. + + + + + + + Identifies the VTL scalar type that is to be converted to an resulting output data type. + + + + + Identifies the resulting output data type the VTL scalar type is to be converted to. If this is an SDMX data type, it must use the proper SimpleDataType enumeration value. For all other data types, a string value can be used to identify the type. + + + + + The format in which the literals of the VTL scalar type are expressed in the transformations. This is only needed if the format is different than the output format expressed by means of the VTL type. + + + + + The format the VTL scalar type has to assume (e.g. YYYY-MM-DD; see VTL specifications), both for the literals in the VTL expressions and for the conversion to the output. + + + + + The value to be produced in the output of the conversion when a component has a null value. + + + + + + + + + + A simple type that allows for a SDMX simple data type enumeration value or a string value for other data types. + + + + + \ No newline at end of file diff --git a/sdmx-ml21/src/test/resources/xml/xsd/schemas/xml.xsd b/sdmx-ml21/src/test/resources/xml/xsd/schemas/xml.xsd new file mode 100644 index 0000000..9294f94 --- /dev/null +++ b/sdmx-ml21/src/test/resources/xml/xsd/schemas/xml.xsd @@ -0,0 +1,80 @@ + + + + + + See http://www.w3.org/XML/1998/namespace.html and + http://www.w3.org/TR/REC-xml for information about this namespace. + + + + + This schema defines attributes and an attribute group + suitable for use by + schemas wishing to allow xml:base, xml:lang or xml:space attributes + on elements they define. + + To enable this, such a schema must import this schema + for the XML namespace, e.g. as follows: + <schema . . .> + . . . + <import namespace="http://www.w3.org/XML/1998/namespace" + schemaLocation="http://www.w3.org/2001/03/xml.xsd"/> + + Subsequently, qualified reference to any of the attributes + or the group defined below will have the desired effect, e.g. + + <type . . .> + . . . + <attributeGroup ref="xml:specialAttrs"/> + + will define a type which will schema-validate an instance + element with any of those attributes + + + + In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + http://www.w3.org/2001/03/xml.xsd. + At the date of issue it can also be found at + http://www.w3.org/2001/xml.xsd. + The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML Schema + itself. In other words, if the XML Schema namespace changes, the version + of this document at + http://www.w3.org/2001/xml.xsd will change + accordingly; the version at + http://www.w3.org/2001/03/xml.xsd will not change. + + + + + + In due course, we should install the relevant ISO 2- and 3-letter + codes as the enumerated possible values . . . + + + + + + + + + + + + + + + See http://www.w3.org/TR/xmlbase/ for + information about this attribute. + + + + + + + + + + diff --git a/sdmx-ml30/build.gradle b/sdmx-ml30/build.gradle new file mode 100644 index 0000000..c158fb4 --- /dev/null +++ b/sdmx-ml30/build.gradle @@ -0,0 +1,48 @@ +plugins { + id 'java' +} + +repositories { + mavenCentral() +} + +apply plugin: 'checkstyle' + +dependencies { + implementation project(":sdmx30-serializer") + implementation project(":sdmx30-infomodel") + + compileOnly("org.projectlombok:lombok:${lombok_version}") + annotationProcessor("org.projectlombok:lombok:${lombok_version}") + + implementation("org.glassfish.jaxb:jaxb-runtime:${xml_bind_jaxb_version}") + implementation("org.apache.logging.log4j:log4j-slf4j2-impl:${log4j_version}") + implementation("org.apache.logging.log4j:log4j-core:${log4j_version}") + implementation("com.epam.deltix:SdmxDataParser:${sdmx_version}") + + implementation("org.mapstruct:mapstruct:${mapstruct_version}") + annotationProcessor("org.mapstruct:mapstruct-processor:${mapstruct_version}") + + implementation("org.apache.commons:commons-collections4:${org_apache_commons_commons_collections4_version}") + implementation("org.apache.commons:commons-lang3:${org_apache_commons_commons_lang3_version}") + implementation("com.fasterxml.jackson.core:jackson-core:${fasterxml_version}") + implementation("com.fasterxml.jackson.core:jackson-databind:${fasterxml_databind_version}") + implementation("com.google.guava:guava:${guava_version}") + implementation "com.opencsv:opencsv:${openc_csv_version}" + + testImplementation("org.projectlombok:lombok:${lombok_version}") + testAnnotationProcessor("org.projectlombok:lombok:${lombok_version}") + + testImplementation("org.springframework:spring-core:${spring_version}") + testImplementation("org.jsonschema2pojo:jsonschema2pojo-core:${jsonschema2pojo_version}") + testImplementation("io.github.benas:random-beans:${random_beans_version}") + testImplementation("org.assertj:assertj-core:${assertj_version}") + testImplementation("net.javacrumbs.json-unit:json-unit:${json_unit_version}") + testImplementation("net.javacrumbs.json-unit:json-unit-assertj:${json_unit_version}") + testImplementation("org.mockito:mockito-core:${mockito_version}") + testImplementation("org.xmlunit:xmlunit-legacy:${xmlunit_legacy_version}") +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/data/StreamingXmlDataWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/data/StreamingXmlDataWriter.java new file mode 100644 index 0000000..3b322c5 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/data/StreamingXmlDataWriter.java @@ -0,0 +1,848 @@ +package com.epam.jsdmx.xml30.data; + +import static java.util.Objects.requireNonNull; + +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.StringJoiner; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Annotation; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinition; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponent; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.serializer.sdmx30.common.ActionType; +import com.epam.jsdmx.serializer.sdmx30.common.DatasetHeader; +import com.epam.jsdmx.serializer.sdmx30.common.DatasetStructureReference; +import com.epam.jsdmx.serializer.sdmx30.common.MetadataAttributeValue; +import com.epam.jsdmx.serializer.sdmx30.common.ProvisionAgreement; +import com.epam.jsdmx.xml30.structure.writer.HeaderWriter; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import lombok.SneakyThrows; +import lombok.extern.log4j.Log4j2; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +@Log4j2 +public class StreamingXmlDataWriter implements XmlDataWriter { + public static final String STRUCTURE_SPECIFIC_DATA = "StructureSpecificData"; + public static final String DATA_SET = "DataSet"; + public static final String STRUCTURE_REF = "structureRef"; + public static final String OBS = "Obs"; + public static final String SERIES = "Series"; + public static final String GROUP = "Group"; + public static final String ATTS = "Atts"; + public static final String ATTRIBUTE = "Attribute"; + public static final String ACTION = "action"; + public static final String VALID_FROM_DATE = "validFromDate"; + public static final String VALID_TO_DATE = "validToDate"; + public static final String METADATA = "Metadata"; + public static final String SCHEMAS_V_3_0_COMMON = "http://www.sdmx.org/resources/sdmxml/schemas/v3_0/common"; + public static final String XML_V_3_0_METADATA = "http://www.sdmx.org/resources/sdmxml/schemas/v3_0/metadata/generic"; + public static final String XML_XS = "http://www.w3.org/2001/XMLSchema"; + public static final String ALL_DIMENSIONS = "AllDimensions"; + public static final String SS = "ss:"; + public static final String COMP = "Comp"; + + private boolean startSeries = false; + private boolean startGroup = false; + private boolean seriesAttribute = false; + private boolean currentDataSetFlat; + private boolean isFirstDataset = true; + + private Boolean isFirstSerie = true; + private Boolean isFirstGroup = true; + + private Map multivaluedMap = new HashMap<>(); + private Map metaAttributeIds = new HashMap<>(); + private Map attributesOfDataset = new HashMap<>(); + private Map> attributesOfDatasetComp = new HashMap<>(); + private Map attributesOfSeries = new HashMap<>(); + private Map> attributesOfSeriesComp = new HashMap<>(); + private Map attributesOfGroup = new HashMap<>(); + private Map> attributesOfGroupComp = new HashMap<>(); + private Map attributesOfObservation = new HashMap<>(); + private Map> attributesOfObservationComp = new HashMap<>(); + private Map> metaAttributesOfDatasetComp = new HashMap<>(); + private Map> metaAttributesOfSeriesComp = new HashMap<>(); + private Map> metaAttributesOfGroupComp = new HashMap<>(); + private Map> metaAttributesOfObservationComp = new HashMap<>(); + private Map observations = new HashMap<>(); + private Map> oneObservationMap = new HashMap<>(); + private Map>> oneObservationMapComp = new HashMap<>(); + private Map dimensionOrder = new HashMap<>(); + private DataStructureDefinition dataStructureDefinition; + + private int observationNumber; + private final XMLStreamWriter writer; + private final HeaderWriter headerWriter; + private boolean dataPresent; + private String dimensionAtObservation; + private String[] currentGroupId; + + public StreamingXmlDataWriter(XMLStreamWriter writer, HeaderWriter headerWriter) { + this.writer = writer; + this.headerWriter = headerWriter; + dataPresent = false; + } + + @Override + @SneakyThrows + public void startDataset(ProvisionAgreement agreement, Artefacts artefacts, DatasetHeader header) { + dataStructureDefinition = CollectionUtils.extractSingleton(artefacts.getDataStructures()); + multivaluedMap.clear(); + dataStructureDefinition.getDataAttributes() + .stream() + .filter(Objects::nonNull) + .forEach(attr -> multivaluedMap.put(attr.getId(), attr.getMaxOccurs() > 1)); + dataStructureDefinition.getMetaAttributeReferences() + .stream() + .filter(Objects::nonNull) + .forEach(attr -> { + multivaluedMap.put(attr.getId(), true); + metaAttributeIds.put(attr.getId(), true); + }); + + final var dimensionPosition = new AtomicInteger(); + final List dimensions = dataStructureDefinition.getDimensions(); + dimensions + .forEach(dim -> dimensionOrder.put(dim.getId(), dimensionPosition.getAndIncrement())); + + DatasetStructureReference datasetStructureReference = header.getDatasetStructureReference(); + ArtefactReference dataStructureReference = datasetStructureReference.getDataStructureReference(); + dimensionAtObservation = datasetStructureReference.getDimensionAtObservation(); + + closePreviousDataset(header); + dataPresent = true; + writeDataSet(dataStructureReference, header); + currentDataSetFlat = ALL_DIMENSIONS.equals(dimensionAtObservation); + if (dataStructureDefinition.getTimeDimension() != null) { + currentGroupId = new String[dimensions.size() - 1]; + } else { + currentGroupId = new String[dimensions.size()]; + } + } + + private void writeHeader(DatasetHeader header) throws XMLStreamException { + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.HEADER); + headerWriter.writeHeaderElements(writer, headerWriter.getDefaultHeaderProvider().provide()); + writeStructure(writer, header); + writer.writeEndElement(); + } + + @SneakyThrows + private void closePreviousDataset(DatasetHeader header) { + if (isFirstDataset) { + writer.writeStartDocument(); + writer.writeStartElement(XmlConstants.MESSAGE + STRUCTURE_SPECIFIC_DATA); + writeNameSpaces(); + writeHeader(header); + isFirstDataset = false; + } else { + if (dataPresent) { + if (!startSeries && !startGroup) { + writeDatasetAttributes(); + } + if (startSeries) { + closeSeries(); + } + if (startGroup) { + closeGroup(); + } + } + writer.writeEndElement(); + } + } + + private void writeStructure(XMLStreamWriter writer, DatasetHeader datasetHeader) throws XMLStreamException { + if (datasetHeader != null && datasetHeader.getDatasetStructureReference() != null) { + DatasetStructureReference datasetStructureReference = datasetHeader.getDatasetStructureReference(); + ArtefactReference dataStructureReference = datasetStructureReference.getDataStructureReference(); + if (dataStructureReference != null) { + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.STRUCTURE_ELEMENT); + String structureRef = getStructureRef(dataStructureReference); + writer.writeAttribute(XmlConstants.STRUCTURE_ID, structureRef); + writer.writeAttribute(XmlConstants.NAMESPACE, dataStructureReference.getMaintainableArtefactReference().getUrn()); + writer.writeAttribute(XmlConstants.DIMENSION_AT_OBSERVATION, datasetStructureReference.getDimensionAtObservation()); + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.STRUCTURE_ELEMENT); + writer.writeCharacters(dataStructureReference.getMaintainableArtefactReference().getUrn()); + writer.writeEndElement(); + writer.writeEndElement(); + } + } + } + + private void writeDataSet(ArtefactReference dataStructureReference, DatasetHeader header) throws XMLStreamException { + writer.writeStartElement(XmlConstants.MESSAGE + DATA_SET); + String structureRef = getStructureRef(dataStructureReference); + ActionType action = header.getAction(); + Instant validFrom = header.getValidFrom(); + Instant validTo = header.getValidTo(); + if (structureRef != null) { + writer.writeAttribute(SS + STRUCTURE_REF, structureRef); + } + if (action != null) { + writer.writeAttribute(ACTION, action.getValue()); + } + if (validFrom != null) { + writer.writeAttribute(VALID_FROM_DATE, validFrom.toString()); + } + if (validTo != null) { + writer.writeAttribute(VALID_TO_DATE, validTo.toString()); + } + } + + private static String getStructureRef(ArtefactReference r) { + if (r == null) { + return null; + } + return r.getOrganisationId() + "." + r.getId() + "." + r.getVersion(); + } + + private void writeNameSpaces() throws XMLStreamException { + writer.writeNamespace("metadata", XML_V_3_0_METADATA); + writer.writeNamespace("common", SCHEMAS_V_3_0_COMMON); + writer.writeNamespace("xs", XML_XS); + writer.writeNamespace("message", XmlConstants.SCHEMAS_V_3_0_MESSAGE); + writer.writeNamespace("xsi", XmlConstants.XMLSCHEMA_INSTANCE); + writer.writeNamespace("xml", XmlConstants.XML_1998_NAMESPACE); + writer.writeNamespace("ss", XmlConstants.SS_NAMESPACE); + writer.writeNamespace("ns1", getCustomNamespace(dataStructureDefinition, dimensionAtObservation)); + + writer.writeAttribute("xsi:schemaLocation", "http://www.sdmx.org/resources/sdmxml/schemas/v3_0/message ../../schemas/SDMXMessage.xsd"); + } + + private static String getCustomNamespace(DataStructureDefinition dsd, String dimAtObs) { + return dsd.getUrn() + ":ObsLevelDim:" + dimAtObs; + } + + @Override + @SneakyThrows + public void startSeries(Annotation... annotations) { + writeDatasetAttributes(); + if (startGroup) { + closeGroup(); + startGroup = false; + } + if (currentDataSetFlat) { + if (Boolean.FALSE.equals(isFirstSerie)) { + closeSeries(); + } + writer.writeStartElement(OBS); + startSeries = true; + isFirstSerie = false; + seriesAttribute = true; + } else { + if (Boolean.FALSE.equals(isFirstSerie)) { + closeSeries(); + } + writer.writeStartElement(SERIES); + startSeries = true; + isFirstSerie = false; + seriesAttribute = true; + } + } + + @SneakyThrows + protected void closeSeries() { + if (currentDataSetFlat) { + closeFlatSeries(); + } else { + writeSeriesAttributes(); + if (!attributesOfSeriesComp.isEmpty()) { + writeAttributeComponents(attributesOfSeriesComp); + } + + if (!metaAttributesOfSeriesComp.isEmpty()) { + writer.writeStartElement(METADATA); + writeMetaAttributeComponents(metaAttributesOfSeriesComp); + writer.writeEndElement(); + } + + attributesOfSeriesComp.clear(); + metaAttributesOfSeriesComp.clear(); + writePreviousObservation(); + writer.writeEndElement(); + } + startSeries = false; + } + + private void closeFlatSeries() throws XMLStreamException { + writeSeriesAttributes(); + + for (Map.Entry> obs : oneObservationMap.entrySet()) { + writeAttributes(obs.getValue()); + writeCompComponents(obs); + } + + if (!attributesOfObservation.isEmpty()) { + writeAttributes(attributesOfObservation); + } + + if (!attributesOfObservationComp.isEmpty()) { + writeAttributeComponents(attributesOfObservationComp); + } + + if (!attributesOfSeriesComp.isEmpty()) { + writeAttributeComponents(attributesOfSeriesComp); + } + + if (!metaAttributesOfObservationComp.isEmpty() || !metaAttributesOfSeriesComp.isEmpty()) { + writer.writeStartElement(METADATA); + if (!metaAttributesOfObservationComp.isEmpty()) { + writeMetaAttributeComponents(metaAttributesOfObservationComp); + } + + if (!metaAttributesOfSeriesComp.isEmpty()) { + writeMetaAttributeComponents(metaAttributesOfSeriesComp); + } + writer.writeEndElement(); + } + + attributesOfObservationComp.clear(); + attributesOfSeriesComp.clear(); + attributesOfObservation.clear(); + observationNumber = 0; + oneObservationMap.clear(); + oneObservationMapComp.clear(); + metaAttributesOfObservationComp.clear(); + metaAttributesOfSeriesComp.clear(); + observations.clear(); + writer.writeEndElement(); + } + + private void writeCompComponents(Map.Entry> obs) throws XMLStreamException { + Map> obsComp = new HashMap<>(); + Map> metaObsComp = new HashMap<>(); + if (oneObservationMapComp.containsKey(obs.getKey())) { + for (var ob : oneObservationMapComp.get(obs.getKey()).entrySet()) { + if (!metaAttributeIds.getOrDefault(ob.getKey(), false)) { + obsComp.put(ob.getKey(), ob.getValue()); + } else { + metaObsComp.put(ob.getKey(), ob.getValue()); + } + } + } + + writeAttributeComponents(obsComp); + if (!attributesOfObservationComp.isEmpty()) { + writeAttributeComponents(attributesOfObservationComp); + } + + if (!metaObsComp.isEmpty() || !metaAttributesOfObservationComp.isEmpty()) { + writer.writeStartElement(METADATA); + writeMetaAttributeComponents(metaObsComp); + writeMetaAttributeComponents(metaAttributesOfObservationComp); + writer.writeEndElement(); + } + } + + private void writeAttributes(Map attributes) throws XMLStreamException { + for (Map.Entry entry : attributes.entrySet()) { + writer.writeAttribute(entry.getKey(), entry.getValue()); + } + } + + @SneakyThrows + protected void closeGroup() { + writeGroupAttributes(); + writer.writeEndElement(); + } + + private String getGroupIdString() { + StringJoiner joiner = new StringJoiner("__"); + for (String groupDimension : currentGroupId) { + if (groupDimension != null) { + joiner.add(groupDimension); + } + } + return joiner.toString(); + } + + @SneakyThrows + private void writeGroupAttributes() { + writeAttributes(attributesOfGroup); + writer.writeAttribute("ns1:type", "GROUP_" + getGroupIdString()); + + if (!attributesOfGroupComp.isEmpty()) { + writeAttributeComponents(attributesOfGroupComp); + } + if (!metaAttributesOfGroupComp.isEmpty()) { + writer.writeStartElement(METADATA); + writeMetaAttributeComponents(metaAttributesOfGroupComp); + writer.writeEndElement(); + } + attributesOfGroupComp.clear(); + metaAttributesOfGroupComp.clear(); + } + + @SneakyThrows + private void writePreviousObservation() { + for (Map.Entry> obs : oneObservationMap.entrySet()) { + writer.writeStartElement(OBS); + + writeAttributes(obs.getValue()); + + if (attributesOfObservation.isEmpty()) { + writeAttributes(attributesOfObservation); + } + + writeCompComponents(obs); + writer.writeEndElement(); + } + attributesOfObservation.clear(); + attributesOfObservationComp.clear(); + observationNumber = 0; + oneObservationMap.clear(); + oneObservationMapComp.clear(); + observations.clear(); + } + + @Override + @SneakyThrows + public void writeSeriesComponent(String concept, String code) { + writer.writeAttribute(concept, code); + } + + @Override + @SneakyThrows + public void startGroup(Annotation... annotations) { + writeDatasetAttributes(); + if (startSeries) { + closeSeries(); + startSeries = false; + } + if (Boolean.FALSE.equals(isFirstGroup)) { + closeGroup(); + } + isFirstGroup = false; + writer.writeStartElement(GROUP); + startGroup = true; + clearCurrentGroupId(); + } + + private void clearCurrentGroupId() { + Arrays.fill(currentGroupId, null); + } + + @Override + @SneakyThrows + public void writeGroupComponent(String concept, String code) { + Integer dimIndex = requireNonNull(dimensionOrder.get(concept), concept + " index was not found"); + currentGroupId[dimIndex] = concept; + writer.writeAttribute(concept, code); + } + + @Override + public void writeObservation(String obsConceptValue, Map measureValues, Annotation[] annotations30) { + writeObservation(null, obsConceptValue, measureValues, annotations30); + } + + @Override + @SneakyThrows + public void writeObservation(String dimAtObsForWrite, String obsConceptValue, Map measureValues, Annotation[] annotations30) { + observationNumber++; + if (currentDataSetFlat) { + if (dimAtObsForWrite != null && !StringUtils.EMPTY.equals(dimAtObsForWrite)) { + writer.writeAttribute(dimAtObsForWrite, obsConceptValue); + } + + if (!measureValues.isEmpty()) { + writeAttributes(measureValues); + } + } else if (startSeries) { + seriesAttribute = false; + + if (dimAtObsForWrite != null && !StringUtils.EMPTY.equals(dimAtObsForWrite)) { + observations.put(dimAtObsForWrite, obsConceptValue); + } + + if (!measureValues.isEmpty()) { + observations.putAll(measureValues); + } + + oneObservationMap.put(observationNumber, new HashMap<>(observations)); + } + } + + @SneakyThrows + private void writeSeriesAttributes() { + if (!attributesOfSeries.isEmpty()) { + writeAttributes(attributesOfSeries); + } + + attributesOfSeries.clear(); + } + + @Override + @SneakyThrows + public void writeAttribute(String concept, String code) { + boolean isMultiValued = multivaluedMap.getOrDefault(concept, false); + boolean isMetaConcept = metaAttributeIds.getOrDefault(concept, false); + if (startSeries && currentDataSetFlat) { + fillStartSeriesDatasetFlat(concept, code, isMultiValued, isMetaConcept); + } else if (startSeries) { + fillStartSeriesAttribute(concept, code, isMultiValued, isMetaConcept); + } else if (startGroup) { + if (isMultiValued) { + if (isMetaConcept) { + metaAttributesOfGroupComp.put(concept, List.of(code)); + } else { + attributesOfGroupComp.put(concept, List.of(code)); + } + } else { + attributesOfGroup.put(concept, code); + } + } else { + if (isMultiValued) { + if (isMetaConcept) { + metaAttributesOfDatasetComp.put(concept, List.of(code)); + } else { + attributesOfDatasetComp.put(concept, List.of(code)); + } + } else { + attributesOfDataset.put(concept, code); + } + } + } + + @Override + @SneakyThrows + public void writeAttribute(String concept, List code) { + if (CollectionUtils.isEmpty(code)) { + return; + } + + boolean isMetaConcept = metaAttributeIds.getOrDefault(concept, false); + if (startSeries) { + fillStartSeriesAttribute(concept, code, isMetaConcept); + } else if (startGroup) { + if (isMetaConcept) { + metaAttributesOfGroupComp.put(concept, code); + } else { + attributesOfGroupComp.put(concept, code); + } + } else { + if (isMetaConcept) { + metaAttributesOfDatasetComp.put(concept, code); + } else { + attributesOfDatasetComp.put(concept, code); + } + } + } + + @Override + public void writeAttribute(String concept, InternationalString value) { + writeInternationalAttributes(concept, List.of(value)); + } + + @Override + @SneakyThrows + public void writeInternationalAttributes(String concept, List values) { + if (CollectionUtils.isEmpty(values)) { + return; + } + + boolean isMetaConcept = metaAttributeIds.getOrDefault(concept, false); + if (startSeries) { + fillStartSeriesAttribute(concept, values, true, isMetaConcept); + } else if (startGroup) { + if (isMetaConcept) { + metaAttributesOfGroupComp.put(concept, values); + } else { + attributesOfGroupComp.put(concept, values); + } + } else { + if (isMetaConcept) { + metaAttributesOfDatasetComp.put(concept, values); + } else { + attributesOfDatasetComp.put(concept, values); + } + } + } + + @Override + @SneakyThrows + public void writeMetaData(MetadataAttributeValue metadataAttributeValue) { + boolean isMultivalued = multivaluedMap.getOrDefault(metadataAttributeValue.getId(), false); + boolean isMetaConcept = metaAttributeIds.getOrDefault(metadataAttributeValue.getId(), false); + final List stringValues = metadataAttributeValue.getStringValues(); + if (startSeries) { + if (currentDataSetFlat) { + if (isMultivalued) { + if (isMetaConcept) { + metaAttributesOfObservationComp.put(metadataAttributeValue.getId(), stringValues); + } else { + attributesOfObservationComp.put(metadataAttributeValue.getId(), stringValues); + } + } else if (!stringValues.isEmpty()) { + attributesOfObservation.put(metadataAttributeValue.getId(), stringValues.get(0)); + } + } else { + fillStartSeriesAttribute(metadataAttributeValue.getId(), metadataAttributeValue.getStringValues(), isMetaConcept); + } + } else { + if (startGroup) { + if (isMultivalued) { + if (isMetaConcept) { + metaAttributesOfGroupComp.put(metadataAttributeValue.getId(), stringValues); + } else { + attributesOfGroupComp.put(metadataAttributeValue.getId(), stringValues); + } + } else if (!stringValues.isEmpty()) { + attributesOfGroup.put(metadataAttributeValue.getId(), stringValues.get(0)); + } + } else { + if (isMultivalued) { + if (isMetaConcept) { + metaAttributesOfDatasetComp.put(metadataAttributeValue.getId(), stringValues); + } else { + attributesOfDatasetComp.put(metadataAttributeValue.getId(), stringValues); + } + } else if (!stringValues.isEmpty()) { + attributesOfDataset.put(metadataAttributeValue.getId(), stringValues.get(0)); + } + } + } + } + + private void fillStartSeriesAttribute(String concept, Object code, boolean isMultiValued, boolean isMeta) { + if (seriesAttribute) { + if (isMultiValued) { + if (isMeta) { + metaAttributesOfSeriesComp.put(concept, code instanceof String ? List.of(code) : getAttributeValue(code)); + } else { + attributesOfSeriesComp.put(concept, code instanceof String ? List.of(code) : getAttributeValue(code)); + } + } else { + attributesOfSeries.put(concept, Objects.toString(code)); + } + } else { + fillObservationAttribute(concept, code, isMultiValued); + } + } + + private void fillStartSeriesAttribute(String concept, List code, boolean isMeta) { + if (seriesAttribute) { + if (isMeta) { + metaAttributesOfSeriesComp.put(concept, code); + } else { + attributesOfSeriesComp.put(concept, code); + } + } else { + fillObservationAttribute(concept, code); + } + } + + private void fillObservationAttribute(String concept, Object code, boolean isMultiValued) { + if (isMultiValued) { + if (oneObservationMapComp.containsKey(observationNumber)) { + oneObservationMapComp.get(observationNumber).put(concept, code instanceof String ? List.of(code) : getAttributeValue(code)); + } else { + HashMap> map = new HashMap<>(); + map.put(concept, code instanceof String ? List.of(code) : getAttributeValue(code)); + oneObservationMapComp.put(observationNumber, map); + } + } else { + if (oneObservationMap.containsKey(observationNumber)) { + oneObservationMap.get(observationNumber).put(concept, Objects.toString(code)); + } else { + HashMap map = new HashMap<>(); + map.put(concept, Objects.toString(code)); + oneObservationMap.put(observationNumber, map); + } + } + } + + private void fillObservationAttribute(String concept, List code) { + if (oneObservationMapComp.containsKey(observationNumber)) { + oneObservationMapComp.get(observationNumber).put(concept, code); + } else { + HashMap> map = new HashMap<>(); + map.put(concept, code); + oneObservationMapComp.put(observationNumber, map); + } + } + + private void fillStartSeriesDatasetFlat(String concept, Object code, boolean isMultiValued, boolean isMeta) { + if (observationNumber != 0) { + fillObservationAttribute(concept, code, isMultiValued); + } else { + if (isMultiValued) { + if (isMeta) { + metaAttributesOfObservationComp.put(concept, code instanceof String ? List.of(code) : getAttributeValue(code)); + } else { + attributesOfObservationComp.put(concept, code instanceof String ? List.of(code) : getAttributeValue(code)); + } + } else { + attributesOfObservation.put(concept, code.toString()); + } + } + } + + private List getAttributeValue(T code) { + if (code instanceof List) { + List list = (List) code; + if (!list.isEmpty()) { + if (list.get(0) instanceof String) { + return getListOfStrings(list); + } else if (list.get(0) instanceof InternationalString) { + return getListOfInternationalStrings(list); + } + } else { + return list; + } + } + + return Collections.emptyList(); + } + + private List getListOfStrings(List list) { + return list.stream().map(Objects::toString).collect(Collectors.toList()); + } + + private List getListOfInternationalStrings(List list) { + return list.stream().map(value -> (InternationalString) value).collect(Collectors.toList()); + } + + + @SneakyThrows + private void writeDatasetAttributes() { + if (!attributesOfDataset.isEmpty() || !attributesOfDatasetComp.isEmpty()) { + writer.writeStartElement(ATTS); + for (var entry : attributesOfDataset.entrySet()) { + writer.writeAttribute(entry.getKey(), entry.getValue()); + } + if (!attributesOfDatasetComp.isEmpty()) { + writeAttributeComponents(attributesOfDatasetComp); + } + writer.writeEndElement(); + } + + if (!metaAttributesOfDatasetComp.isEmpty()) { + writer.writeStartElement(METADATA); + writeMetaAttributeComponents(metaAttributesOfDatasetComp); + writer.writeEndElement(); + } + + attributesOfDataset.clear(); + attributesOfDatasetComp.clear(); + metaAttributesOfDatasetComp.clear(); + } + + private void writeAttributeComponents(Map> map) throws XMLStreamException { + writeComponents(map, false); + } + + private void writeMetaAttributeComponents(Map> map) throws XMLStreamException { + writeComponents(map, true); + } + + private void writeComponents(Map> map, boolean isMetaConcept) throws XMLStreamException { + for (var attrComp : map.entrySet()) { + if (attrComp.getValue().get(0) instanceof String) { + var valuesList = getListOfStrings(attrComp.getValue()); + if (isMetaConcept) { + writeMetaComp(attrComp.getKey(), valuesList); + } else { + writeComp(attrComp.getKey(), valuesList); + } + } else { + var valuesList = getListOfInternationalStrings(attrComp.getValue()); + writeInternationalStringComp(attrComp.getKey(), valuesList, isMetaConcept); + } + } + } + + private void writeComp(String id, List values) throws XMLStreamException { + if (!isStringCollectionEmpty(values)) { + writer.writeStartElement(COMP); + writer.writeAttribute(XmlConstants.ID, id); + for (String value : values) { + if (StringUtils.isNotEmpty(value)) { + writer.writeStartElement(XmlConstants.VALUE); + writer.writeCharacters(value); + writer.writeEndElement(); + } + } + writer.writeEndElement(); + } + } + + private void writeMetaComp(String id, List values) throws XMLStreamException { + if (!isStringCollectionEmpty(values)) { + if (metaAttributeIds.getOrDefault(id, false)) { + writer.writeStartElement(ATTRIBUTE); + writer.writeAttribute(XmlConstants.ID, id); + for (String value : values) { + if (StringUtils.isNotEmpty(value)) { + writer.writeStartElement(XmlConstants.VALUE); + writer.writeCharacters(value); + writer.writeEndElement(); + } + } + writer.writeEndElement(); + } + } + } + + @SneakyThrows + private void writeInternationalStringComp(String concept, List valuesList, boolean isMetaConcept) { + if (isMetaConcept) { + writer.writeStartElement(ATTRIBUTE); + } else { + writer.writeStartElement(COMP); + } + writer.writeAttribute(XmlConstants.ID, concept); + for (var values : valuesList) { + writer.writeStartElement(XmlConstants.VALUE); + values.getAll().forEach((key, value) -> { + try { + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.TEXT); + writer.writeAttribute(XmlConstants.XML_LANG, key); + writer.writeCharacters(value); + writer.writeEndElement(); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + }); + writer.writeEndElement(); + } + writer.writeEndElement(); + } + + private boolean isStringCollectionEmpty(List values) { + return CollectionUtils.isEmpty(values) + || values.stream().noneMatch(StringUtils::isNotEmpty); + } + + @Override + @SneakyThrows + public void close() { + if (dataPresent) { + writeDatasetAttributes(); + if (startSeries) { + closeSeries(); + } + if (startGroup) { + closeGroup(); + } + writer.writeEndElement(); + writer.writeEndDocument(); + dataPresent = false; + } + writer.close(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/data/XmlDataWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/data/XmlDataWriter.java new file mode 100644 index 0000000..e5fb786 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/data/XmlDataWriter.java @@ -0,0 +1,8 @@ +package com.epam.jsdmx.xml30.data; + + +import com.epam.jsdmx.serializer.sdmx30.common.DataWriter; + +public interface XmlDataWriter extends DataWriter { + +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/AgencySchemeReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/AgencySchemeReader.java new file mode 100644 index 0000000..4aa9d4a --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/AgencySchemeReader.java @@ -0,0 +1,103 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setExternalReference; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setId; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setServiceUrl; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setStructureUrl; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setUri; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setValidFrom; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setValidTo; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Agency; +import com.epam.jsdmx.infomodel.sdmx30.AgencyImpl; +import com.epam.jsdmx.infomodel.sdmx30.AgencySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Version; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public class AgencySchemeReader extends XmlReader { + + private final OrganisationReader organisationReader; + + private final List agencies = new ArrayList<>(); + + public AgencySchemeReader(AnnotableReader annotableReader, + NameableReader nameableReader, + OrganisationReader organisationReader) { + super(annotableReader, nameableReader); + this.organisationReader = organisationReader; + } + + @Override + protected AgencySchemeImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + AgencySchemeImpl agencyScheme = super.read(reader); + agencyScheme.setItems(new ArrayList<>(agencies)); + return agencyScheme; + } + + @Override + protected void read(XMLStreamReader reader, AgencySchemeImpl agencyScheme) throws URISyntaxException, XMLStreamException { + String name = reader.getLocalName(); + if (!XmlConstants.AGENCY.equals(name)) { + throw new IllegalArgumentException("AgencyScheme " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + + Agency agency = organisationReader.addOrganisation(reader, new AgencyImpl(), null); + agencies.add(agency); + } + + @Override + protected String getName() { + return XmlConstants.AGENCY_SCHEME; + } + + @Override + protected String getNames() { + return XmlConstants.AGENCY_SCHEMES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getAgencySchemes().addAll(artefacts); + } + + @Override + protected AgencySchemeImpl createMaintainableArtefact() { + return new AgencySchemeImpl(); + } + + @Override + protected void setAttributes(XMLStreamReader reader, AgencySchemeImpl artefact) throws XMLStreamException { + setUri(reader, artefact); + + setStructureUrl(reader, artefact); + + setServiceUrl(reader, artefact); + + setId(reader, artefact); + + artefact.setOrganizationId("SDMX"); + + artefact.setVersion(Version.createFromString(XmlConstants.DEFAULT_VERSION)); + + setExternalReference(reader, artefact); + + setValidTo(reader, artefact); + + setValidFrom(reader, artefact); + } + + @Override + protected void clean() { + agencies.clear(); + } +} + diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/AnnotableReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/AnnotableReader.java new file mode 100644 index 0000000..f25936d --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/AnnotableReader.java @@ -0,0 +1,98 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.AnnotableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.Annotation; +import com.epam.jsdmx.infomodel.sdmx30.AnnotationImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.InternationalUri; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class AnnotableReader { + + public void setAnnotations(XMLStreamReader reader, AnnotableArtefact artefact) throws XMLStreamException, URISyntaxException { + List annotations = getAnnotations(reader); + artefact.getAnnotations().addAll(annotations); + } + + public List getAnnotations(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + List annotations = new ArrayList<>(); + Map urls = new HashMap<>(); + Map texts = new HashMap<>(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.COM_ANNOTATIONS)) { + String localName = reader.getLocalName(); + if (XmlConstants.COM_ANNOTATION.equals(localName)) { + fillAnnotation(reader, annotations, urls, texts); + } + moveToNextTag(reader); + } + return annotations; + } + + private void fillAnnotation(XMLStreamReader reader, + List annotations, + Map urls, + Map texts) throws XMLStreamException, URISyntaxException { + var annotation = new AnnotationImpl(); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .ifPresent(annotation::setId); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.COM_ANNOTATION)) { + String local = reader.getLocalName(); + switch (local) { + case XmlConstants.COM_ANNOTATION_TITLE: + annotation.setTitle(reader.getElementText()); + break; + case XmlConstants.COM_ANNOTATION_TYPE: + annotation.setType(reader.getElementText()); + break; + case XmlConstants.COM_ANNOTATION_TEXT: + readOneInternationalStringAndPutToMap(reader, texts); + break; + case XmlConstants.COM_ANNOTATION_VALUE: + annotation.setValue(reader.getElementText()); + break; + case XmlConstants.COM_ANNOTATION_URL: + String locale = reader.getAttributeValue(XmlConstants.XML_1998_NAMESPACE, XmlConstants.LANG); + String text = reader.getElementText(); + if (locale != null && text != null) { + urls.put(locale, new URI(text)); + } + break; + default: + throw new IllegalStateException("Annotation does not support element: " + local); + } + moveToNextTag(reader); + } + annotation.setUrl(urls.isEmpty() ? null : new InternationalUri(urls)); + annotation.setText(texts.isEmpty() ? null : new InternationalString(texts)); + annotations.add(annotation); + } + + private void readOneInternationalStringAndPutToMap(XMLStreamReader reader, + Map map) throws XMLStreamException { + String locale = reader.getAttributeValue(XmlConstants.XML_1998_NAMESPACE, XmlConstants.LANG); + String text = reader.getElementText(); + if (locale != null && text != null) { + map.put(locale, text); + } + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/AttributeListReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/AttributeListReader.java new file mode 100644 index 0000000..c597f4a --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/AttributeListReader.java @@ -0,0 +1,196 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.readConceptIdentity; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.readConceptRole; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.AttributeRelationship; +import com.epam.jsdmx.infomodel.sdmx30.DataAttribute; +import com.epam.jsdmx.infomodel.sdmx30.DataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.GroupRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeRef; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeRefImpl; +import com.epam.jsdmx.infomodel.sdmx30.ObservationRelationshipImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +@AllArgsConstructor +public class AttributeListReader { + + private final RepresentationReader representationReader; + private final AnnotableReader annotableReader; + + public void read(XMLStreamReader reader, AttributeDescriptorImpl attributeDescriptor) throws XMLStreamException, URISyntaxException { + attributeDescriptor.setId(XmlConstants.ATTRIBUTE_DESCRIPTOR_ID); + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + attributeDescriptor.setUri(new URI(uri)); + } + List components = new ArrayList<>(); + List metadataAttributeRefs = new ArrayList<>(); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.ATTRIBUTE_LIST)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, attributeDescriptor); + break; + case XmlConstants.ATTRIBUTE: + setAttribute(reader, components); + break; + case XmlConstants.METADATA_ATTRIBUTE_USAGE: + metadataAttributeRefs.add(getMetaAttributeRefs(reader)); + break; + default: + throw new IllegalArgumentException("AttributeList " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + attributeDescriptor.setMetadataAttributes(metadataAttributeRefs); + attributeDescriptor.setComponents(components); + } + + private MetadataAttributeRef getMetaAttributeRefs(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + var metadataAttributeRef = new MetadataAttributeRefImpl(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.METADATA_ATTRIBUTE_USAGE)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, metadataAttributeRef); + break; + case XmlConstants.METADATA_ATTRIBUTE_REFERENCE: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(metadataAttributeRef::setId); + break; + case XmlConstants.ATTRIBUTE_RELATIONSHIP: + metadataAttributeRef.setMetadataRelationship(getAttributeRelationship(reader)); + break; + default: + throw new IllegalArgumentException("MetadataAttributeUsage " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + return metadataAttributeRef; + } + + private void setAttribute(XMLStreamReader reader, List components) throws XMLStreamException, URISyntaxException { + var attribute = new DataAttributeImpl(); + List conceptRoles = new ArrayList<>(); + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .ifPresent(attribute::setId); + + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + attribute.setUri(new URI(uri)); + } + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.ATTRIBUTE)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, attribute); + break; + case XmlConstants.CONCEPT_IDENTITY: + readConceptIdentity(reader, attribute); + break; + case XmlConstants.CONCEPT_ROLE: + readConceptRole(reader, conceptRoles); + break; + case XmlConstants.LOCAL_REPRESENTATION: + attribute.setLocalRepresentation(representationReader.readRepresentation(reader)); + break; + case XmlConstants.ATTRIBUTE_RELATIONSHIP: + attribute.setAttributeRelationship(getAttributeRelationship(reader)); + break; + case XmlConstants.MEASURE_RELATIONSHIP: + setMeasureRelationship(reader, attribute); + break; + default: + throw new IllegalArgumentException("Attribute " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + attribute.setConceptRoles(conceptRoles); + attribute.setMaxOccurs(1); // todo: write to correct fields + components.add(attribute); + } + + private void setMeasureRelationship(XMLStreamReader reader, DataAttributeImpl attribute) throws XMLStreamException { + List measures = new ArrayList<>(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.MEASURE_RELATIONSHIP)) { + String localName = reader.getLocalName(); + if (!XmlConstants.MEASURE.equals(localName)) { + throw new IllegalArgumentException("MeasureRelationship " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(measures::add); + + moveToNextTag(reader); + } + var measureRelationship = new MeasureRelationshipImpl(); + measureRelationship.setMeasures(CollectionUtils.isNotEmpty(measures) ? measures : null); + attribute.setMeasureRelationship(measureRelationship); + } + + private AttributeRelationship getAttributeRelationship(XMLStreamReader reader) throws XMLStreamException { + List dimensions = new ArrayList<>(); + var dimensionRelationship = new DimensionRelationshipImpl(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.ATTRIBUTE_RELATIONSHIP)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.DATAFLOW: + moveToNextTag(reader); + moveToNextTag(reader); + return null; + case XmlConstants.DIMENSION: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(dimensions::add); + break; + case XmlConstants.OBSERVATION: + moveToNextTag(reader); + moveToNextTag(reader); + return new ObservationRelationshipImpl(); + case XmlConstants.GROUP: + var group = new GroupRelationshipImpl(); + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(group::setGroupKey); + + moveToNextTag(reader); + return group; + default: + throw new IllegalArgumentException("AttributeRelationship " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + + dimensionRelationship.setDimensions(dimensions); + return dimensionRelationship; + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CategorisationReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CategorisationReader.java new file mode 100644 index 0000000..05c2927 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CategorisationReader.java @@ -0,0 +1,68 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.net.URISyntaxException; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CategorisationImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public class CategorisationReader extends XmlReader { + + public CategorisationReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @Override + protected CategorisationImpl createMaintainableArtefact() { + return new CategorisationImpl(); + } + + @Override + protected void read(XMLStreamReader reader, CategorisationImpl categorisation) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.SOURCE: + String source = reader.getElementText(); + if (XmlReaderUtils.isNotEmptyOrNullElementText(source)) { + IdentifiableArtefactReferenceImpl artefactReference = new IdentifiableArtefactReferenceImpl(source); + categorisation.setCategorizedArtefact(artefactReference); + } + break; + case XmlConstants.TARGET: + String target = reader.getElementText(); + if (XmlReaderUtils.isNotEmptyOrNullElementText(target)) { + IdentifiableArtefactReferenceImpl artefactReference = new IdentifiableArtefactReferenceImpl(target); + categorisation.setCategorizedBy(artefactReference); + } + break; + default: + throw new IllegalArgumentException("Categorisation " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + } + + @Override + protected void setAttributes(XMLStreamReader reader, CategorisationImpl maintainableArtefact) throws XMLStreamException { + XmlReaderUtils.setCommonAttributes(reader, maintainableArtefact); + } + + @Override + protected String getName() { + return XmlConstants.CATEGORISATION; + } + + @Override + protected String getNames() { + return XmlConstants.CATEGORISATIONS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getCategorisations().addAll(artefacts); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeMapReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeMapReader.java new file mode 100644 index 0000000..ce19c0c --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeMapReader.java @@ -0,0 +1,85 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public class CategorySchemeMapReader extends XmlReader implements ItemSchemeMapReader { + + private final List itemMaps = new ArrayList<>(); + + public CategorySchemeMapReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @Override + protected CategorySchemeMapImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + CategorySchemeMapImpl categorySchemeMap = super.read(reader); + categorySchemeMap.setItemMaps(new ArrayList<>(itemMaps)); + return categorySchemeMap; + } + + @Override + protected void read(XMLStreamReader reader, CategorySchemeMapImpl categorySchemeMap) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.SOURCE: + Optional.ofNullable(reader.getElementText()) + .map(MaintainableArtefactReference::new) + .ifPresent(categorySchemeMap::setSource); + break; + case XmlConstants.TARGET: + Optional.ofNullable(reader.getElementText()) + .map(MaintainableArtefactReference::new) + .ifPresent(categorySchemeMap::setTarget); + break; + case XmlConstants.ITEM_MAP: + itemMaps.add(getItemMap(reader, annotableReader)); + break; + default: + throw new IllegalArgumentException("CategorySchemeMap " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + } + + @Override + protected CategorySchemeMapImpl createMaintainableArtefact() { + return new CategorySchemeMapImpl(); + } + + @Override + protected void setAttributes(XMLStreamReader reader, CategorySchemeMapImpl maintainableArtefact) throws XMLStreamException { + XmlReaderUtils.setCommonAttributes(reader, maintainableArtefact); + } + + @Override + protected String getName() { + return XmlConstants.CATEGORY_SCHEME_MAP; + } + + @Override + protected String getNames() { + return XmlConstants.CATEGORY_SCHEME_MAPS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getCategorySchemeMaps().addAll(artefacts); + } + + @Override + protected void clean() { + itemMaps.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeReader.java new file mode 100644 index 0000000..ce62a0c --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeReader.java @@ -0,0 +1,125 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Category; +import com.epam.jsdmx.infomodel.sdmx30.CategoryImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class CategorySchemeReader extends XmlReader { + + private final List categories = new ArrayList<>(); + + public CategorySchemeReader(AnnotableReader annotableReader, NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @Override + protected CategorySchemeImpl createMaintainableArtefact() { + return new CategorySchemeImpl(); + } + + @Override + protected CategorySchemeImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + CategorySchemeImpl categoryScheme = super.read(reader); + categoryScheme.setItems(new ArrayList<>(categories)); + return categoryScheme; + } + + @Override + protected void read(XMLStreamReader reader, CategorySchemeImpl maintainableArtefact) throws URISyntaxException, XMLStreamException { + String name = reader.getLocalName(); + if (!XmlConstants.CATEGORY.equals(name)) { + throw new IllegalArgumentException("CategoryScheme " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + + Category categoryList = addCategory(reader); + categories.add(categoryList); + } + + @Override + protected String getName() { + return XmlConstants.CATEGORY_SCHEME; + } + + @Override + protected String getNames() { + return XmlConstants.CATEGORY_SCHEMES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getCategorySchemes().addAll(artefacts); + } + + private Category addCategory(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + List hierarchy = new ArrayList<>(); + var category = new CategoryImpl(); + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .ifPresent(category::setId); + + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + category.setUri(new URI(uri)); + } + + Map names = new HashMap<>(); + Map descriptions = new HashMap<>(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.CATEGORY)) { + String name = reader.getLocalName(); + switch (name) { + case XmlConstants.COM_ANNOTATIONS: + this.annotableReader.setAnnotations(reader, category); + break; + case XmlConstants.COM_NAME: + this.nameableReader.setNameable(reader, names); + break; + case XmlConstants.COM_DESCRIPTION: + this.nameableReader.setNameable(reader, descriptions); + break; + case XmlConstants.CATEGORY: + hierarchy.add(addCategory(reader)); + break; + default: + throw new IllegalArgumentException("Category " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + moveToNextTag(reader); + } + category.setName(names.isEmpty() ? null : new InternationalString(names)); + category.setDescription(descriptions.isEmpty() ? null : new InternationalString(descriptions)); + category.setHierarchy(hierarchy); + return category; + } + + @Override + protected void setAttributes(XMLStreamReader reader, CategorySchemeImpl categoryScheme) throws XMLStreamException { + XmlReaderUtils.setCommonAttributes(reader, categoryScheme); + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_PARTIAL)) + .map(Boolean::parseBoolean) + .ifPresent(categoryScheme::setPartial); + } + + @Override + protected void clean() { + categories.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodeImplReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodeImplReader.java new file mode 100644 index 0000000..723bdc0 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodeImplReader.java @@ -0,0 +1,6 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import com.epam.jsdmx.infomodel.sdmx30.CodeImpl; + +public class CodeImplReader implements CodeReader { +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodeReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodeReader.java new file mode 100644 index 0000000..357d53d --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodeReader.java @@ -0,0 +1,109 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Code; +import com.epam.jsdmx.infomodel.sdmx30.CodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public interface CodeReader { + + default void setCodeElements(XMLStreamReader reader, + T code, + NameableReader nameableReader, + AnnotableReader annotableReader, + Map codeWithParentId) throws XMLStreamException, URISyntaxException { + Map names = new HashMap<>(); + Map descriptions = new HashMap<>(); + String parentId = null; + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.CODE, XmlConstants.GEO_FEATURE_SET_CODE, XmlConstants.GEO_GRID_CODES)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_NAME: + nameableReader.setNameable(reader, names); + break; + case XmlConstants.COM_DESCRIPTION: + nameableReader.setNameable(reader, descriptions); + break; + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, code); + break; + case XmlConstants.STRUCTURE_PARENT: + parentId = reader.getElementText(); + code.setParentId(parentId); + break; + default: + readCodeSpecialFields(reader, code, localName); + break; + } + moveToNextTag(reader); + } + code.setName(names.isEmpty() ? null : new InternationalString(names)); + code.setDescription(descriptions.isEmpty() ? null : new InternationalString(descriptions)); + codeWithParentId.put(code, parentId); + } + + default void readCodeSpecialFields(XMLStreamReader reader, T code, String localName) throws XMLStreamException { + throw new IllegalArgumentException("Code does not support " + localName); + } + + default void setCodeAttributes(XMLStreamReader reader, T code) throws URISyntaxException { + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .ifPresent(code::setId); + + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + code.setUri(new URI(uri)); + } + } + + default void setCode(XMLStreamReader reader, + T code, + NameableReader nameableReader, + AnnotableReader annotableReader, + Map codeWithParentId) throws URISyntaxException, XMLStreamException { + setCodeAttributes(reader, code); + setCodeElements(reader, code, nameableReader, annotableReader, codeWithParentId); + } + + default List formCodesWithHierarchy(Map codeWithParentId) { + Map> parentAndChildrenCodes = codeWithParentId.entrySet() + .stream() + .filter(cod -> cod.getValue() != null) + .collect(Collectors.groupingBy( + Map.Entry::getValue, + Collectors.mapping(Map.Entry::getKey, Collectors.toList()) + )); + Set codes = codeWithParentId.keySet(); + for (Map.Entry> entry : parentAndChildrenCodes.entrySet()) { + Optional parentCode = codes.stream() + .filter(cod -> cod.getId().equals(entry.getKey())) + .findFirst(); + parentCode.ifPresent(code -> { + List value = entry.getValue().stream() + .map(Code.class::cast) + .collect(Collectors.toList()); + code.setHierarchy(value); + }); + } + return new ArrayList<>(codes); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodelistExtensionReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodelistExtensionReader.java new file mode 100644 index 0000000..3d2c3a9 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodelistExtensionReader.java @@ -0,0 +1,82 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.CascadeValue; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.ExclusiveCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.InclusiveCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.MemberValue; +import com.epam.jsdmx.infomodel.sdmx30.MemberValueImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class CodelistExtensionReader { + + public CodelistExtensionImpl getCodelistExtension(XMLStreamReader reader) throws XMLStreamException { + moveToNextTag(reader); + var codelistExtension = new CodelistExtensionImpl(); + while (isNotEndingTag(reader, XmlConstants.CODELIST_EXTENSION)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.INCLUSIVE_CODE_SELECTION: + var inclusiveCodeSelection = new InclusiveCodeSelectionImpl(); + setMemberValues(inclusiveCodeSelection, reader); + codelistExtension.setCodeSelection(inclusiveCodeSelection); + break; + case XmlConstants.EXCLUSIVE_CODE_SELECTION: + var exclusiveCodeSelection = new ExclusiveCodeSelectionImpl(); + setMemberValues(exclusiveCodeSelection, reader); + codelistExtension.setCodeSelection(exclusiveCodeSelection); + break; + case XmlConstants.CODELIST: + String clText = reader.getElementText(); + codelistExtension.setCodelist(new MaintainableArtefactReference(clText)); + break; + default: + throw new IllegalArgumentException("CodelistExtension " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + return codelistExtension; + } + + private void setMemberValues(ExclusiveCodeSelectionImpl exclusiveCodeSelection, XMLStreamReader reader) throws XMLStreamException { + List memberValues = getMemberValues(reader); + exclusiveCodeSelection.setMembers(memberValues); + } + + private void setMemberValues(InclusiveCodeSelectionImpl inclusiveCodeSelection, XMLStreamReader reader) throws XMLStreamException { + List memberValues = getMemberValues(reader); + inclusiveCodeSelection.setMembers(memberValues); + } + + private List getMemberValues(XMLStreamReader reader) throws XMLStreamException { + List memberValues = new ArrayList<>(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.INCLUSIVE_CODE_SELECTION, XmlConstants.EXCLUSIVE_CODE_SELECTION)) { + String localName = reader.getLocalName(); + if (XmlConstants.MEMBER_VALUE.equals(localName)) { + var memberValue = new MemberValueImpl(); + String cascadeValues = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.CASCADE_VALUES); + memberValue.setCascadeValue(CascadeValue.valueOf(cascadeValues.toUpperCase())); + String value = reader.getElementText(); + if (XmlReaderUtils.isNotEmptyOrNullElementText(value)) { + memberValue.setValue(value); + } + memberValues.add(memberValue); + } + moveToNextTag(reader); + } + return memberValues; + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodelistReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodelistReader.java new file mode 100644 index 0000000..a5f20eb --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/CodelistReader.java @@ -0,0 +1,107 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Code; +import com.epam.jsdmx.infomodel.sdmx30.CodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class CodelistReader extends XmlReader { + + private final CodelistExtensionReader codelistExtensionReader; + private final CodeImplReader codeImplReader; + private final List codes = new ArrayList<>(); + private final List codelistExtensions = new ArrayList<>(); + Map codeWithParentId = new HashMap<>(); + + public CodelistReader(AnnotableReader annotableReader, + NameableReader nameableReader, + CodelistExtensionReader codelistExtensionReader, CodeImplReader codeImplReader) { + super(annotableReader, nameableReader); + this.codelistExtensionReader = codelistExtensionReader; + this.codeImplReader = codeImplReader; + } + + @Override + protected CodelistImpl createMaintainableArtefact() { + return new CodelistImpl(); + } + + @Override + protected CodelistImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + CodelistImpl codelist = super.read(reader); + codelist.setItems(new ArrayList<>(codes)); + codelist.setExtensions(new ArrayList<>(codelistExtensions)); + return codelist; + } + + @Override + protected void read(XMLStreamReader reader, CodelistImpl codelist) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.STR_CODE: + var code = new CodeImpl(); + codeImplReader.setCode( + reader, + code, + nameableReader, + annotableReader, + codeWithParentId + ); + codes.add(code); + break; + case XmlConstants.CODELIST_EXTENSION: + String prefix = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.PREFIX); + CodelistExtensionImpl codelistExtension = codelistExtensionReader.getCodelistExtension(reader); + codelistExtension.setPrefix(prefix); + codelistExtensions.add(codelistExtension); + break; + default: + throw new IllegalArgumentException("Codelist " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + } + + @Override + protected void setAttributes(XMLStreamReader reader, CodelistImpl codelist) throws XMLStreamException { + XmlReaderUtils.setCommonAttributes(reader, codelist); + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_PARTIAL)) + .map(Boolean::parseBoolean) + .ifPresent(codelist::setPartial); + } + + @Override + protected String getName() { + return XmlConstants.CODELIST; + } + + @Override + protected String getNames() { + return XmlConstants.CODELISTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getCodelists().addAll(artefacts); + } + + @Override + protected void clean() { + codes.clear(); + codelistExtensions.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeMapReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeMapReader.java new file mode 100644 index 0000000..4f6aa5f --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeMapReader.java @@ -0,0 +1,86 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public class ConceptSchemeMapReader extends XmlReader implements ItemSchemeMapReader { + + private final List itemMaps = new ArrayList<>(); + + public ConceptSchemeMapReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @Override + protected ConceptSchemeMapImpl createMaintainableArtefact() { + return new ConceptSchemeMapImpl(); + } + + @Override + protected ConceptSchemeMapImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + ConceptSchemeMapImpl conceptSchemeMap = super.read(reader); + conceptSchemeMap.setItemMaps(new ArrayList<>(itemMaps)); + return conceptSchemeMap; + } + + @Override + protected void read(XMLStreamReader reader, ConceptSchemeMapImpl conceptSchemeMap) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.SOURCE: + Optional.ofNullable(reader.getElementText()) + .map(MaintainableArtefactReference::new) + .ifPresent(conceptSchemeMap::setSource); + break; + case XmlConstants.TARGET: + Optional.ofNullable(reader.getElementText()) + .map(MaintainableArtefactReference::new) + .ifPresent(conceptSchemeMap::setTarget); + break; + case XmlConstants.ITEM_MAP: + itemMaps.add(getItemMap(reader, annotableReader)); + break; + default: + throw new IllegalArgumentException("CategorySchemeMap " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + + } + + @Override + protected void setAttributes(XMLStreamReader reader, ConceptSchemeMapImpl maintainableArtefact) throws XMLStreamException { + XmlReaderUtils.setCommonAttributes(reader, maintainableArtefact); + } + + @Override + protected String getName() { + return XmlConstants.CONCEPT_SCHEME_MAP; + } + + @Override + protected String getNames() { + return XmlConstants.CONCEPT_SCHEME_MAPS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getConceptSchemeMaps().addAll(artefacts); + } + + @Override + protected void clean() { + itemMaps.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeReader.java new file mode 100644 index 0000000..2808b96 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeReader.java @@ -0,0 +1,167 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setCommonAttributes; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Concept; +import com.epam.jsdmx.infomodel.sdmx30.ConceptImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.IsoConceptReferenceImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class ConceptSchemeReader extends XmlReader { + + private final RepresentationReader representationReader; + private final List items = new ArrayList<>(); + + public ConceptSchemeReader(AnnotableReader annotableReader, + NameableReader nameableReader, + RepresentationReader representationReader) { + super(annotableReader, nameableReader); + this.representationReader = representationReader; + } + + @Override + protected ConceptSchemeImpl createMaintainableArtefact() { + return new ConceptSchemeImpl(); + } + + @Override + protected ConceptSchemeImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + ConceptSchemeImpl conceptScheme = super.read(reader); + conceptScheme.setItems(List.copyOf(items)); + + return conceptScheme; + } + + @Override + protected void read(XMLStreamReader reader, ConceptSchemeImpl conceptScheme) throws URISyntaxException, XMLStreamException { + var concept = new ConceptImpl(); + String localName = reader.getLocalName(); + + if (!XmlConstants.CONCEPT.equals(localName)) { + throw new IllegalArgumentException("ConceptScheme " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .ifPresent(concept::setId); + + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + concept.setUri(new URI(uri)); + } + + readElements(reader, concept); + items.add(concept); + } + + @Override + protected void clean() { + this.items.clear(); + } + + @Override + protected void setAttributes(XMLStreamReader reader, ConceptSchemeImpl maintainableArtefact) throws XMLStreamException { + setCommonAttributes(reader, maintainableArtefact); + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_PARTIAL)) + .map(Boolean::parseBoolean) + .ifPresent(maintainableArtefact::setPartial); + } + + @Override + protected String getName() { + return XmlConstants.CONCEPT_SCHEME; + } + + @Override + protected String getNames() { + return XmlConstants.CONCEPT_SCHEMES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getConceptSchemes().addAll(artefacts); + } + + private void readElements(XMLStreamReader reader, ConceptImpl concept) throws XMLStreamException, URISyntaxException { + Map names = new HashMap<>(); + Map descriptions = new HashMap<>(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.CONCEPT)) { + String name = reader.getLocalName(); + switch (name) { + case XmlConstants.COM_ANNOTATIONS: + this.annotableReader.setAnnotations(reader, concept); + break; + case XmlConstants.COM_NAME: + this.nameableReader.setNameable(reader, names); + break; + case XmlConstants.COM_DESCRIPTION: + this.nameableReader.setNameable(reader, descriptions); + break; + case XmlConstants.ISOCONCEPT_REFERENCE: + readIsoReference(reader, concept); + break; + case XmlConstants.CORE_REPRESENTATION: + concept.setCoreRepresentation(representationReader.readRepresentation(reader)); + break; + case XmlConstants.PARENT: + // skip it. Hierarchical concepts are not supported + while (isNotEndingTag(reader, XmlConstants.PARENT)) { + moveToNextTag(reader); + } + break; + default: + throw new IllegalArgumentException("Concept " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + moveToNextTag(reader); + } + concept.setName(names.isEmpty() ? null : new InternationalString(names)); + concept.setDescription(descriptions.isEmpty() ? null : new InternationalString(descriptions)); + } + + private void readIsoReference(XMLStreamReader reader, ConceptImpl concept) throws XMLStreamException { + var isoConceptReference = new IsoConceptReferenceImpl(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.ISOCONCEPT_REFERENCE)) { + String name = reader.getLocalName(); + switch (name) { + case XmlConstants.CONCEPT_ID: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(isoConceptReference::setConceptId); + break; + case XmlConstants.CONCEPT_AGENCY: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(isoConceptReference::setAgency); + break; + case XmlConstants.CONCEPT_SCHEME_ID: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(isoConceptReference::setSchemeId); + break; + default: + throw new IllegalArgumentException("ISOConceptReference " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + concept.setIsoConceptReference(isoConceptReference); + moveToNextTag(reader); + } + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataConstraintReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataConstraintReader.java new file mode 100644 index 0000000..a904653 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataConstraintReader.java @@ -0,0 +1,269 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.net.URISyntaxException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ComponentValue; +import com.epam.jsdmx.infomodel.sdmx30.ComponentValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegion; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionImpl; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionKey; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionKeyImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataKey; +import com.epam.jsdmx.infomodel.sdmx30.DataKeyImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySet; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySetImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.SelectionValue; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class DataConstraintReader extends XmlReader { + + private final List constrainedArtefacts = new ArrayList<>(); + private final ReleaseCalendarReader releaseCalendarReader; + private final MemberSelectionReader memberSelectionReader; + List cubeRegions = new ArrayList<>(); + List dataKeySets = new ArrayList<>(); + + public DataConstraintReader(AnnotableReader annotableReader, + NameableReader nameableReader, + ReleaseCalendarReader releaseCalendarReader, + MemberSelectionReader memberSelectionReader) { + super(annotableReader, nameableReader); + this.releaseCalendarReader = releaseCalendarReader; + this.memberSelectionReader = memberSelectionReader; + } + + @Override + protected DataConstraintImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + DataConstraintImpl dataConstraint = super.read(reader); + dataConstraint.setCubeRegions(new ArrayList<>(cubeRegions)); + dataConstraint.setDataContentKeys(new ArrayList<>(dataKeySets)); + dataConstraint.setConstrainedArtefacts(new ArrayList<>(constrainedArtefacts)); + return dataConstraint; + } + + @Override + protected void read(XMLStreamReader reader, DataConstraintImpl maintainableArtefact) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.CONSTRAINT_ATTACHMENT: + readConstraintsAttachments(reader); + break; + case XmlConstants.RELEASE_CALENDAR: + maintainableArtefact.setReleaseCalendar(releaseCalendarReader.getReleaseCalendar(reader)); + break; + case XmlConstants.CUBE_REGION: + cubeRegions.add(getCubeRegion(reader)); + break; + case XmlConstants.DATA_KEY_SET: + dataKeySets.add(getDataKeySet(reader)); + break; + default: + throw new IllegalArgumentException("DataConstraint " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + } + + @Override + protected DataConstraintImpl createMaintainableArtefact() { + return new DataConstraintImpl(); + } + + private DataKeySet getDataKeySet(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + var dataKeySet = new DataKeySetImpl(); + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_INCLUDED)) + .map(Boolean::parseBoolean) + .ifPresent(dataKeySet::setIncluded); + + List keys = new ArrayList<>(); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.DATA_KEY_SET)) { + String localName = reader.getLocalName(); + if (!XmlConstants.KEY.equals(localName)) { + throw new IllegalArgumentException("DataKeySet " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + keys.add(getKey(reader)); + moveToNextTag(reader); + } + dataKeySet.setKeys(keys); + return dataKeySet; + } + + private DataKey getKey(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + var dataKey = new DataKeyImpl(); + List keyValues = new ArrayList<>(); + List memberSelections = new ArrayList<>(); + String validTo = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VALID_TO); + String validFrom = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VALID_FROM); + dataKey.setValidFrom(validFrom == null ? null : Instant.parse(validFrom)); + dataKey.setValidTo(validTo == null ? null : Instant.parse(validTo)); + dataKey.setIncluded(XmlReaderUtils.getIncluded(reader)); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.KEY)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, dataKey); + break; + case XmlConstants.COMPONENT: + memberSelections.add(memberSelectionReader.getMemberSelection(reader)); + break; + case XmlConstants.KEY_VALUE: + keyValues.add(getComponentValues(reader)); + break; + default: + throw new IllegalArgumentException("DataKey " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + dataKey.setKeyValues(keyValues); + dataKey.setMemberSelections(memberSelections); + return dataKey; + } + + private ComponentValue getComponentValues(XMLStreamReader reader) throws XMLStreamException { + var componentValue = new ComponentValueImpl(); + + componentValue.setIncluded(XmlReaderUtils.getIncluded(reader)); + componentValue.setRemovePrefix(XmlReaderUtils.getRemovePrefix(reader)); + componentValue.setComponentId(XmlReaderUtils.getId(reader)); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.COMPONENT, XmlConstants.KEY_VALUE)) { + String localName = reader.getLocalName(); + if (!XmlConstants.VALUE.equals(localName)) { + throw new IllegalArgumentException("ComponentValue " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(componentValue::setValue); + + moveToNextTag(reader); + } + return componentValue; + } + + private CubeRegion getCubeRegion(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + var cubeRegion = new CubeRegionImpl(); + List memberSelections = new ArrayList<>(); + List keyValues = new ArrayList<>(); + cubeRegion.setIncluded(XmlReaderUtils.getIncluded(reader)); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.CUBE_REGION)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, cubeRegion); + break; + case XmlConstants.COMPONENT: + memberSelections.add(memberSelectionReader.getMemberSelection(reader)); + break; + case XmlConstants.KEY_VALUE: + keyValues.add(getCubeRegionKeys(reader)); + break; + default: + throw new IllegalArgumentException("CubeRegion " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + cubeRegion.setMemberSelections(memberSelections); + cubeRegion.setCubeRegionKeys(keyValues); + return cubeRegion; + } + + private CubeRegionKey getCubeRegionKeys(XMLStreamReader reader) throws XMLStreamException { + var cubeRegion = new CubeRegionKeyImpl(); + String validTo = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VALID_TO); + String validFrom = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VALID_FROM); + + if (XmlReaderUtils.isNotEmptyOrNullElementText(validTo)) { + cubeRegion.setValidTo(Instant.parse(validTo)); + } + + if (XmlReaderUtils.isNotEmptyOrNullElementText(validFrom)) { + cubeRegion.setValidFrom(Instant.parse(validFrom)); + } + cubeRegion.setIncluded(XmlReaderUtils.getIncluded(reader)); + cubeRegion.setRemovePrefix(XmlReaderUtils.getRemovePrefix(reader)); + cubeRegion.setComponentId(XmlReaderUtils.getId(reader)); + + List selectionValues = memberSelectionReader.getSelectionValues(reader); + cubeRegion.setSelectionValues(selectionValues); + return cubeRegion; + } + + private void readConstraintsAttachments(XMLStreamReader reader) throws XMLStreamException { + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.CONSTRAINT_ATTACHMENT)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.DATA_PROVIDER: + case XmlConstants.DATA_STRUCTURE: + case XmlConstants.DATAFLOW: + case XmlConstants.PROVISION_AGREEMENT: + addArtefactReference(reader); + break; + default: + throw new IllegalArgumentException("ConstraintsAttachments " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + } + + private void addArtefactReference(XMLStreamReader reader) throws XMLStreamException { + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(IdentifiableArtefactReferenceImpl::new) + .ifPresent(constrainedArtefacts::add); + } + + @Override + protected void setAttributes(XMLStreamReader reader, DataConstraintImpl dataConstraint) throws XMLStreamException { + XmlReaderUtils.setCommonAttributes(reader, dataConstraint); + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ROLE_ATTR)) + .map(XmlConstants.STRING_CONSTRAINT_ROLE::get) + .ifPresent(dataConstraint::setConstraintRoleType); + } + + @Override + protected String getName() { + return XmlConstants.DATA_CONSTRAINT; + } + + @Override + protected String getNames() { + return XmlConstants.DATA_CONSTRAINTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getDataConstraints().addAll(artefacts); + } + + @Override + protected void clean() { + constrainedArtefacts.clear(); + cubeRegions.clear(); + dataKeySets.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataConsumerSchemeReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataConsumerSchemeReader.java new file mode 100644 index 0000000..a63cc63 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataConsumerSchemeReader.java @@ -0,0 +1,117 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setAgencyId; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setExternalReference; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setServiceUrl; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setStructureUrl; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setUri; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setValidFrom; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setValidTo; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumer; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class DataConsumerSchemeReader extends XmlReader { + + private final OrganisationReader organisationReader; + private final List dataConsumers = new ArrayList<>(); + private final Map dataConsumerWithParent = new HashMap<>(); + + public DataConsumerSchemeReader(AnnotableReader annotableReader, + NameableReader nameableReader, + OrganisationReader organisationReader) { + super(annotableReader, nameableReader); + this.organisationReader = organisationReader; + } + + @Override + protected DataConsumerSchemeImpl createMaintainableArtefact() { + return new DataConsumerSchemeImpl(); + } + + @Override + protected DataConsumerSchemeImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + DataConsumerSchemeImpl dataConsumerScheme = super.read(reader); + Map> dataConsumerListMap = organisationReader.formHierarchy(dataConsumerWithParent); + for (Map.Entry> consumersHier : dataConsumerListMap.entrySet()) { + List value = consumersHier.getValue(); + List hierarchy = new ArrayList<>(value); + consumersHier.getKey().setHierarchy(hierarchy); + } + dataConsumerScheme.setItems(new ArrayList<>(dataConsumers)); + return dataConsumerScheme; + } + + @Override + protected void read(XMLStreamReader reader, DataConsumerSchemeImpl maintainableArtefact) throws URISyntaxException, XMLStreamException { + String name = reader.getLocalName(); + if (!XmlConstants.DATA_CONSUMER.equals(name)) { + throw new IllegalArgumentException("DataConsumerScheme " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + + } + DataConsumer dataConsumer = organisationReader.addOrganisation(reader, new DataConsumerImpl(), dataConsumerWithParent); + dataConsumers.add(dataConsumer); + } + + @Override + protected void setAttributes(XMLStreamReader reader, DataConsumerSchemeImpl artefact) throws XMLStreamException { + setUri(reader, artefact); + + setStructureUrl(reader, artefact); + + setServiceUrl(reader, artefact); + + artefact.setId(XmlConstants.DATA_CONSUMERS); + + artefact.setVersion(Version.createFromString(XmlConstants.DEFAULT_VERSION)); + + setAgencyId(reader, artefact); + + setExternalReference(reader, artefact); + + setValidTo(reader, artefact); + + setValidFrom(reader, artefact); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_PARTIAL)) + .map(Boolean::parseBoolean) + .ifPresent(artefact::setPartial); + } + + @Override + protected String getName() { + return XmlConstants.DATA_CONSUMER_SCHEME; + } + + @Override + protected String getNames() { + return XmlConstants.DATA_CONSUMER_SCHEMES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getDataConsumerSchemes().addAll(artefacts); + } + + @Override + protected void clean() { + dataConsumers.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataProviderSchemeReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataProviderSchemeReader.java new file mode 100644 index 0000000..db3259b --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataProviderSchemeReader.java @@ -0,0 +1,110 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataProvider; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class DataProviderSchemeReader extends XmlReader { + + private final OrganisationReader organisationReader; + + private final List dataProviders = new ArrayList<>(); + private final Map dataProviderStringMap = new HashMap<>(); + + public DataProviderSchemeReader(AnnotableReader annotableReader, + NameableReader nameableReader, + OrganisationReader organisationReader) { + super(annotableReader, nameableReader); + this.organisationReader = organisationReader; + } + + @Override + protected DataProviderSchemeImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + DataProviderSchemeImpl dataProviderScheme = super.read(reader); + Map> dataProviderListMap = organisationReader.formHierarchy(dataProviderStringMap); + for (Map.Entry> consumersHier : dataProviderListMap.entrySet()) { + List value = consumersHier.getValue(); + List hierarchy = new ArrayList<>(value); + consumersHier.getKey().setHierarchy(hierarchy); + } + dataProviderScheme.setItems(new ArrayList<>(dataProviders)); + return dataProviderScheme; + } + + @Override + protected void read(XMLStreamReader reader, DataProviderSchemeImpl maintainableArtefact) throws URISyntaxException, XMLStreamException { + String name = reader.getLocalName(); + if (!XmlConstants.DATA_PROVIDER.equals(name)) { + throw new IllegalArgumentException("DataProviderScheme " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + + } + DataProvider dataProvider = organisationReader.addOrganisation(reader, new DataProviderImpl(), dataProviderStringMap); + dataProviders.add(dataProvider); + } + + @Override + protected DataProviderSchemeImpl createMaintainableArtefact() { + return new DataProviderSchemeImpl(); + } + + @Override + protected void setAttributes(XMLStreamReader reader, DataProviderSchemeImpl artefact) throws XMLStreamException { + XmlReaderUtils.setUri(reader, artefact); + + XmlReaderUtils.setStructureUrl(reader, artefact); + + XmlReaderUtils.setServiceUrl(reader, artefact); + + artefact.setId(XmlConstants.DATA_PROVIDERS); + + artefact.setVersion(Version.createFromString(XmlConstants.DEFAULT_VERSION)); + + XmlReaderUtils.setAgencyId(reader, artefact); + + XmlReaderUtils.setExternalReference(reader, artefact); + + XmlReaderUtils.setValidTo(reader, artefact); + + XmlReaderUtils.setValidFrom(reader, artefact); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_PARTIAL)) + .map(Boolean::parseBoolean) + .ifPresent(artefact::setPartial); + } + + @Override + protected String getName() { + return XmlConstants.DATA_PROVIDER_SCHEME; + } + + @Override + protected String getNames() { + return XmlConstants.DATA_PROVIDER_SCHEMES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getDataProviderSchemes().addAll(artefacts); + } + + @Override + protected void clean() { + dataProviders.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataStructureDefinitionReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataStructureDefinitionReader.java new file mode 100644 index 0000000..a3e17df --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataStructureDefinitionReader.java @@ -0,0 +1,113 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.net.URISyntaxException; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptorImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public class DataStructureDefinitionReader extends XmlReader { + + private final AttributeListReader attributeListReader; + private final DimensionListReader dimensionListReader; + private final MeasureListReader measureListReader; + + public DataStructureDefinitionReader(AnnotableReader annotableReader, + NameableReader nameableReader, + AttributeListReader attributeListReader, + DimensionListReader dimensionListReader, + MeasureListReader measureListReader) { + super(annotableReader, nameableReader); + this.attributeListReader = attributeListReader; + this.dimensionListReader = dimensionListReader; + this.measureListReader = measureListReader; + } + + @Override + protected DataStructureDefinitionImpl createMaintainableArtefact() { + return new DataStructureDefinitionImpl(); + } + + @Override + protected void read(XMLStreamReader reader, DataStructureDefinitionImpl dsd) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.METADATA: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(MaintainableArtefactReference::new) + .ifPresent(dsd::setMetadataStructure); + break; + case XmlConstants.DATA_STRUCTURE_COMPONENTS: + readDataStructures(reader, dsd); + break; + default: + throw new IllegalArgumentException("DataStructureDefinition " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + } + + private void readDataStructures(XMLStreamReader reader, DataStructureDefinitionImpl dsd) throws XMLStreamException, URISyntaxException { + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.DATA_STRUCTURE_COMPONENTS)) { + String name = reader.getLocalName(); + switch (name) { + case XmlConstants.ATTRIBUTE_LIST: + var attributeDescriptor = new AttributeDescriptorImpl(); + attributeListReader.read(reader, attributeDescriptor); + dsd.setAttributeDescriptor(attributeDescriptor); + break; + case XmlConstants.DIMENSION_LIST: + var dimensionDescriptor = new DimensionDescriptorImpl(); + dimensionListReader.read(reader, dimensionDescriptor); + dsd.setDimensionDescriptor(dimensionDescriptor); + break; + case XmlConstants.MEASURE_LIST: + var measureDescriptor = new MeasureDescriptorImpl(); + measureListReader.read(reader, measureDescriptor); + dsd.setMeasureDescriptor(measureDescriptor); + break; + case XmlConstants.GROUP: + // Skip it + while (isNotEndingTag(reader, XmlConstants.GROUP)) { + moveToNextTag(reader); + } + break; + default: + throw new IllegalArgumentException("DataStructureComponents " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + moveToNextTag(reader); + } + } + + @Override + protected void setAttributes(XMLStreamReader reader, DataStructureDefinitionImpl maintainableArtefact) throws XMLStreamException { + XmlReaderUtils.setCommonAttributes(reader, maintainableArtefact); + } + + @Override + protected String getName() { + return XmlConstants.DATA_STRUCTURE; + } + + @Override + protected String getNames() { + return XmlConstants.DATA_STRUCTURES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getDataStructures().addAll(artefacts); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataflowReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataflowReader.java new file mode 100644 index 0000000..f342291 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DataflowReader.java @@ -0,0 +1,61 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setCommonAttributes; + +import java.net.URISyntaxException; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public class DataflowReader extends XmlReader { + + public DataflowReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @Override + protected DataflowImpl createMaintainableArtefact() { + return new DataflowImpl(); + } + + @Override + protected void read(XMLStreamReader reader, DataflowImpl dataflow) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + if (!XmlConstants.STRUCTURE_UPPER.equals(localName)) { + throw new IllegalArgumentException("Dataflow " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(MaintainableArtefactReference::new) + .ifPresent(dataflow::setStructure); + } + + @Override + protected void setAttributes(XMLStreamReader reader, DataflowImpl maintainableArtefact) throws XMLStreamException { + setCommonAttributes(reader, maintainableArtefact); + } + + @Override + protected String getName() { + return XmlConstants.DATAFLOW; + } + + @Override + protected String getNames() { + return XmlConstants.DATAFLOWS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getDataflows().addAll(artefacts); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DimensionListReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DimensionListReader.java new file mode 100644 index 0000000..fd7d82c --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/DimensionListReader.java @@ -0,0 +1,140 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponent; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.TimeDimensionImpl; +import com.epam.jsdmx.serializer.util.DimensionUtil; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +@AllArgsConstructor +public class DimensionListReader { + + private final RepresentationReader representationReader; + private final AnnotableReader annotableReader; + + public void read(XMLStreamReader reader, DimensionDescriptorImpl dimensionDescriptor) throws URISyntaxException, XMLStreamException { + dimensionDescriptor.setId(XmlConstants.DIMENSION_DESCRIPTOR_ID); + String dimUri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (dimUri != null) { + dimensionDescriptor.setUri(new URI(dimUri)); + } + + List dimensions = new ArrayList<>(); + List timeDimensions = new ArrayList<>(); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.DIMENSION_LIST)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, dimensionDescriptor); + break; + case XmlConstants.TIME_DIMENSION: + setTimeDimensions(reader, timeDimensions); + break; + case XmlConstants.DIMENSION: + setDimensions(reader, dimensions); + break; + default: + throw new IllegalArgumentException("DimensionList " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + List dimensionComponents = new ArrayList<>(); + dimensionComponents.addAll(dimensions); + dimensionComponents.addAll(timeDimensions); + + DimensionUtil.populateZeroBasedOrder(dimensionComponents); + + dimensionDescriptor.setComponents(CollectionUtils.isEmpty(dimensionComponents) ? null : dimensionComponents); + } + + private void setTimeDimensions(XMLStreamReader reader, List timeDimensions) throws URISyntaxException, XMLStreamException { + var timeDimension = new TimeDimensionImpl(); + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .ifPresent(timeDimension::setId); + + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + timeDimension.setUri(new URI(uri)); + } + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.TIME_DIMENSION)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, timeDimension); + break; + case XmlConstants.CONCEPT_IDENTITY: + XmlReaderUtils.readConceptIdentity(reader, timeDimension); + break; + case XmlConstants.LOCAL_REPRESENTATION: + timeDimension.setLocalRepresentation(representationReader.readRepresentation(reader)); + break; + default: + throw new IllegalArgumentException("TimeDimension " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + timeDimensions.add(timeDimension); + } + + private void setDimensions(XMLStreamReader reader, List dimensions) throws URISyntaxException, XMLStreamException { + var dimension = new DimensionImpl(); + List conceptRoles = new ArrayList<>(); + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .ifPresent(dimension::setId); + + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + dimension.setUri(new URI(uri)); + } + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.POSITION)) + .map(Integer::parseInt) + .ifPresent(dimension::setOrder); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.DIMENSION)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, dimension); + break; + case XmlConstants.CONCEPT_IDENTITY: + XmlReaderUtils.readConceptIdentity(reader, dimension); + break; + case XmlConstants.LOCAL_REPRESENTATION: + dimension.setLocalRepresentation(representationReader.readRepresentation(reader)); + break; + case XmlConstants.CONCEPT_ROLE: + XmlReaderUtils.readConceptRole(reader, conceptRoles); + break; + default: + throw new IllegalArgumentException("Dimension " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + dimension.setConceptRoles(conceptRoles); + dimensions.add(dimension); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GeoFeatureSetCodeReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GeoFeatureSetCodeReader.java new file mode 100644 index 0000000..d74ec3f --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GeoFeatureSetCodeReader.java @@ -0,0 +1,21 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.net.URISyntaxException; +import java.util.Optional; + +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCodeImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class GeoFeatureSetCodeReader implements CodeReader { + + @Override + public void setCodeAttributes(XMLStreamReader reader, GeoFeatureSetCodeImpl code) throws URISyntaxException { + CodeReader.super.setCodeAttributes(reader, code); + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VALUE_LOWER)) + .ifPresent(code::setValue); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GeoGridCodelistReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GeoGridCodelistReader.java new file mode 100644 index 0000000..13449c6 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GeoGridCodelistReader.java @@ -0,0 +1,105 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeoGridCodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.GridCodeImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class GeoGridCodelistReader extends XmlReader { + + private final CodelistExtensionReader codelistExtensionReader; + private final GridCodeReader gridCodeReader; + private final List codes = new ArrayList<>(); + private final List codelistExtensions = new ArrayList<>(); + Map codeWithParentId = new HashMap<>(); + + public GeoGridCodelistReader(AnnotableReader annotableReader, + NameableReader nameableReader, + CodelistExtensionReader codelistExtensionReader, + GridCodeReader gridCodeReader) { + super(annotableReader, nameableReader); + this.codelistExtensionReader = codelistExtensionReader; + this.gridCodeReader = gridCodeReader; + } + + @Override + protected GeoGridCodelistImpl createMaintainableArtefact() { + return new GeoGridCodelistImpl(); + } + + @Override + protected GeoGridCodelistImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + GeoGridCodelistImpl geoGridCodelist = super.read(reader); + + geoGridCodelist.setItems(List.copyOf(codes)); + geoGridCodelist.setExtensions(new ArrayList<>(codelistExtensions)); + return geoGridCodelist; + } + + @Override + protected void read(XMLStreamReader reader, GeoGridCodelistImpl geoGridCodelist) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.GEO_GRID_CODES: + var code = new GridCodeImpl(); + gridCodeReader.setCode( + reader, + code, + nameableReader, + annotableReader, + codeWithParentId + ); + codes.add(code); + break; + case XmlConstants.CODELIST_EXTENSION: + String prefix = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.PREFIX); + CodelistExtensionImpl codelistExtension = codelistExtensionReader.getCodelistExtension(reader); + codelistExtension.setPrefix(prefix); + codelistExtensions.add(codelistExtension); + break; + case XmlConstants.GRID_DEFINITION: + geoGridCodelist.setGridDefinition(reader.getElementText()); + break; + default: + throw new IllegalArgumentException("GeoGridCodelist " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + } + + @Override + protected void setAttributes(XMLStreamReader reader, GeoGridCodelistImpl geoGridCodelist) throws XMLStreamException { + XmlReaderUtils.setCommonAttributes(reader, geoGridCodelist); + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_PARTIAL)) + .map(Boolean::parseBoolean) + .ifPresent(geoGridCodelist::setPartial); + } + + @Override + protected String getName() { + return XmlConstants.GEOGRID_CODELIST; + } + + @Override + protected String getNames() { + return XmlConstants.GEOGRID_CODELISTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getGeoGridCodelists().addAll(artefacts); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GeographicCodelistReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GeographicCodelistReader.java new file mode 100644 index 0000000..fa80c4b --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GeographicCodelistReader.java @@ -0,0 +1,107 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCode; +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeographicCodelistImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class GeographicCodelistReader extends XmlReader { + + private final GeoFeatureSetCodeReader geoFeatureSetCodeReader; + private final CodelistExtensionReader codelistExtensionReader; + private final List codes = new ArrayList<>(); + private final List codelistExtensions = new ArrayList<>(); + Map codeWithParentId = new HashMap<>(); + + public GeographicCodelistReader(AnnotableReader annotableReader, + NameableReader nameableReader, + GeoFeatureSetCodeReader geoFeatureSetCodeReader, + CodelistExtensionReader codelistExtensionReader) { + super(annotableReader, nameableReader); + this.geoFeatureSetCodeReader = geoFeatureSetCodeReader; + this.codelistExtensionReader = codelistExtensionReader; + } + + @Override + protected GeographicCodelistImpl createMaintainableArtefact() { + return new GeographicCodelistImpl(); + } + + @Override + protected GeographicCodelistImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + GeographicCodelistImpl geographicCodelist = super.read(reader); + geographicCodelist.setItems(List.copyOf(codes)); + geographicCodelist.setExtensions(new ArrayList<>(codelistExtensions)); + return geographicCodelist; + } + + @Override + protected void read(XMLStreamReader reader, GeographicCodelistImpl maintainableArtefact) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.GEO_FEATURE_SET_CODE: + var code = new GeoFeatureSetCodeImpl(); + geoFeatureSetCodeReader.setCode( + reader, + code, + nameableReader, + annotableReader, + codeWithParentId + ); + codes.add(code); + break; + case XmlConstants.CODELIST_EXTENSION: + String prefix = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.PREFIX); + CodelistExtensionImpl codelistExtension = codelistExtensionReader.getCodelistExtension(reader); + codelistExtension.setPrefix(prefix); + codelistExtensions.add(codelistExtension); + break; + default: + throw new IllegalArgumentException("GeographicalCodelist " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + } + + @Override + protected void setAttributes(XMLStreamReader reader, GeographicCodelistImpl geographicCodelist) throws XMLStreamException { + XmlReaderUtils.setCommonAttributes(reader, geographicCodelist); + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_PARTIAL)) + .map(Boolean::parseBoolean) + .ifPresent(geographicCodelist::setPartial); + } + + @Override + protected String getName() { + return XmlConstants.GEO_CODELIST; + } + + @Override + protected String getNames() { + return XmlConstants.GEO_CODELISTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getGeographicCodelists().addAll(artefacts); + } + + @Override + protected void clean() { + codes.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GridCodeReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GridCodeReader.java new file mode 100644 index 0000000..9cd4c2e --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/GridCodeReader.java @@ -0,0 +1,18 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.GridCodeImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public class GridCodeReader implements CodeReader { + + @Override + public void readCodeSpecialFields(XMLStreamReader reader, GridCodeImpl code, String localName) throws XMLStreamException { + if (!XmlConstants.GEO_CELL.equals(localName)) { + throw new IllegalArgumentException("GridCode does not support " + localName); + } + code.setGeoCell(reader.getElementText()); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/HeaderReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/HeaderReader.java new file mode 100644 index 0000000..bee3784 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/HeaderReader.java @@ -0,0 +1,70 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.time.Instant; +import java.util.List; +import java.util.Optional; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.serializer.sdmx30.common.Header; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class HeaderReader { + + public static final String ID = "ID"; + public static final String TEST = "Test"; + public static final String PREPARED = "Prepared"; + public static final String SENDER = "Sender"; + public static final String RECEIVER = "Receiver"; + + public Header read(XMLStreamReader reader) throws XMLStreamException { + var header = new Header(); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.HEADER)) { + String localName = reader.getLocalName(); + switch (localName) { + case ID: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(header::setId); + break; + case TEST: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(test -> header.setTest(Boolean.parseBoolean(test))); + break; + case PREPARED: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(prepared -> header.setPrepared(Instant.parse(prepared))); + break; + case SENDER: + var party = new Party(); + String sender = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID); + party.setId(sender); + XmlReaderUtils.getPartyNames(reader, party); + header.setSender(party); + break; + case RECEIVER: + var partyReceiver = new Party(); + String receiver = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID); + partyReceiver.setId(receiver); + XmlReaderUtils.getPartyNames(reader, partyReceiver); + header.setReceivers(List.of(partyReceiver)); + break; + default: + throw new IllegalArgumentException("Header " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + return header; + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/HierarchyAssociationReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/HierarchyAssociationReader.java new file mode 100644 index 0000000..ca365b7 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/HierarchyAssociationReader.java @@ -0,0 +1,77 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setCommonAttributes; + +import java.net.URISyntaxException; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyAssociationImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public class HierarchyAssociationReader extends XmlReader { + + public HierarchyAssociationReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @Override + protected HierarchyAssociationImpl createMaintainableArtefact() { + return new HierarchyAssociationImpl(); + } + + @Override + protected void read(XMLStreamReader reader, HierarchyAssociationImpl hierarchyAssociation) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.LINKED_HIERARCHY: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(MaintainableArtefactReference::new) + .ifPresent(hierarchyAssociation::setLinkedHierarchy); + break; + case XmlConstants.LINKED_OBJECT: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(MaintainableArtefactReference::new) + .ifPresent(hierarchyAssociation::setLinkedObject); + break; + case XmlConstants.CONTEXT_OBJECT: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(MaintainableArtefactReference::new) + .ifPresent(hierarchyAssociation::setContextObject); + break; + default: + throw new IllegalArgumentException("HierarchyAssociation " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + + } + + @Override + protected void setAttributes(XMLStreamReader reader, HierarchyAssociationImpl hierarchyAssociation) { + setCommonAttributes(reader, hierarchyAssociation); + } + + @Override + protected String getName() { + return XmlConstants.HIERARCHY_ASSOCIATION; + } + + @Override + protected String getNames() { + return XmlConstants.HIERARCHY_ASSOCIATIONS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getHierarchyAssociations().addAll(artefacts); + } + +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/HierarchyReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/HierarchyReader.java new file mode 100644 index 0000000..45fbce3 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/HierarchyReader.java @@ -0,0 +1,199 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.net.URI; +import java.net.URISyntaxException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.BaseFacetImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodingFormatImpl; +import com.epam.jsdmx.infomodel.sdmx30.FacetType; +import com.epam.jsdmx.infomodel.sdmx30.HierarchicalCode; +import com.epam.jsdmx.infomodel.sdmx30.HierarchicalCodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.LevelImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import lombok.SneakyThrows; +import org.apache.commons.lang3.StringUtils; + +public class HierarchyReader extends XmlReader { + + public HierarchyReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @SneakyThrows + private static void readCodeAttributes(XMLStreamReader reader, HierarchicalCodeImpl code) { + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .ifPresent(code::setId); + + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + code.setUri(new URI(uri)); + } + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VALID_TO)) + .map(Instant::parse) + .ifPresent(code::setValidTo); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VALID_FROM)) + .map(Instant::parse) + .ifPresent(code::setValidFrom); + } + + @Override + protected HierarchyImpl createMaintainableArtefact() { + return new HierarchyImpl(); + } + + @Override + protected void read(XMLStreamReader reader, HierarchyImpl hierarchy) throws URISyntaxException, XMLStreamException { + List codes = new ArrayList<>(); + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.LEVEL: + hierarchy.setLevel(getLevel(reader)); + break; + case XmlConstants.HIERARCHICAL_CODE: + HierarchicalCode code = addHierarchicalCode(reader); + codes.add(code); + break; + default: + throw new IllegalArgumentException("Hierarchy " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + hierarchy.setCodes(codes); + + } + + @Override + protected void setAttributes(XMLStreamReader reader, HierarchyImpl hierarchy) { + XmlReaderUtils.setCommonAttributes(reader, hierarchy); + } + + @Override + protected String getName() { + return XmlConstants.HIERARCHY; + } + + @Override + protected String getNames() { + return XmlConstants.HIERARCHIES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getHierarchies().addAll(artefacts); + } + + private HierarchicalCode addHierarchicalCode(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + var code = new HierarchicalCodeImpl(); + List hierarchicalCodes = new ArrayList<>(); + readCodeAttributes(reader, code); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.HIERARCHICAL_CODE)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + this.annotableReader.setAnnotations(reader, code); + break; + case XmlConstants.CODE: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(IdentifiableArtefactReferenceImpl::new) + .ifPresent(code::setCode); + break; + case XmlConstants.LEVEL: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(code::setLevelId); + break; + case XmlConstants.HIERARCHICAL_CODE: + hierarchicalCodes.add(addHierarchicalCode(reader)); + break; + default: + throw new IllegalArgumentException("HierarchicalCode " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + code.setHierarchicalCodes(hierarchicalCodes); + return code; + } + + @SneakyThrows + private LevelImpl getLevel(XMLStreamReader reader) { + var level = new LevelImpl(); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .ifPresent(level::setId); + + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + level.setUri(new URI(uri)); + } + + Map names = new HashMap<>(); + Map descriptions = new HashMap<>(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.LEVEL)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + this.annotableReader.setAnnotations(reader, level); + break; + case XmlConstants.COM_NAME: + this.nameableReader.setNameable(reader, names); + break; + case XmlConstants.COM_DESCRIPTION: + this.nameableReader.setNameable(reader, descriptions); + break; + case XmlConstants.CODING_FORMAT: + setCodingFormat(reader, level); + break; + case XmlConstants.LEVEL: + level.setChild(getLevel(reader)); + break; + default: + throw new IllegalArgumentException("Level " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + level.setName(names.isEmpty() ? null : new InternationalString(names)); + level.setDescription(descriptions.isEmpty() ? null : new InternationalString(descriptions)); + + return level; + } + + private void setCodingFormat(XMLStreamReader reader, LevelImpl level) throws XMLStreamException { + if (reader.getAttributeCount() > 0) { + QName format = reader.getAttributeName(0); + String codeFormat = format.getLocalPart(); + String formatValue = reader.getAttributeValue(StringUtils.EMPTY, codeFormat); + var codingFormat = new CodingFormatImpl(); + var facet = new BaseFacetImpl(); + facet.setType(FacetType.valueOf(XmlConstants.MAP_CODING_FORMAT.get(codeFormat))); + facet.setValue(formatValue); + codingFormat.setCodingFormat(facet); + level.setCodeFormat(List.of(codingFormat)); + } + moveToNextTag(reader); + } + +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ItemSchemeMapReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ItemSchemeMapReader.java new file mode 100644 index 0000000..c5ae2ca --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ItemSchemeMapReader.java @@ -0,0 +1,48 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.net.URISyntaxException; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.infomodel.sdmx30.ItemMapImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public interface ItemSchemeMapReader { + + default ItemMap getItemMap(XMLStreamReader reader, AnnotableReader annotableReader) throws XMLStreamException, URISyntaxException { + var itemMap = new ItemMapImpl(); + itemMap.setValidFrom(XmlReaderUtils.getDate(reader, XmlConstants.VALID_FROM)); + itemMap.setValidTo(XmlReaderUtils.getDate(reader, XmlConstants.VALID_TO)); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.ITEM_MAP)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, itemMap); + break; + case XmlConstants.SOURCE_VALUE: + String source = reader.getElementText(); + if (source != null) { + itemMap.setSource(source); + } + break; + case XmlConstants.TARGET_VALUE: + String target = reader.getElementText(); + if (target != null) { + itemMap.setTarget(target); + } + break; + default: + throw new IllegalArgumentException("ItemMap " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + return itemMap; + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MappedComponent.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MappedComponent.java new file mode 100644 index 0000000..5a68598 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MappedComponent.java @@ -0,0 +1,13 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MappedComponent { + private String source; + private String target; +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MeasureListReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MeasureListReader.java new file mode 100644 index 0000000..dd32f4b --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MeasureListReader.java @@ -0,0 +1,87 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Measure; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +@AllArgsConstructor +public class MeasureListReader { + + private final RepresentationReader representationReader; + private final AnnotableReader annotableReader; + + public void read(XMLStreamReader reader, MeasureDescriptorImpl measureDescriptor) throws URISyntaxException, XMLStreamException { + measureDescriptor.setId(XmlConstants.MEASURE_DESCRIPTOR_ID); + List measureList = new ArrayList<>(); + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + measureDescriptor.setUri(new URI(uri)); + } + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.MEASURE_LIST)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, measureDescriptor); + break; + case XmlConstants.MEASURE: + setMeasure(reader, measureList); + break; + default: + throw new IllegalArgumentException("MeasureList " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + measureDescriptor.setComponents(CollectionUtils.isEmpty(measureList) ? null : measureList); + } + + private void setMeasure(XMLStreamReader reader, List measureList) throws XMLStreamException, URISyntaxException { + var measure = new MeasureImpl(); + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .ifPresent(measure::setId); + + List conceptRoles = new ArrayList<>(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.MEASURE)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, measure); + break; + case XmlConstants.CONCEPT_IDENTITY: + XmlReaderUtils.readConceptIdentity(reader, measure); + break; + case XmlConstants.LOCAL_REPRESENTATION: + measure.setLocalRepresentation(representationReader.readRepresentation(reader)); + break; + case XmlConstants.CONCEPT_ROLE: + XmlReaderUtils.readConceptRole(reader, conceptRoles); + break; + default: + throw new IllegalArgumentException("Measure " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + measure.setConceptRoles(conceptRoles); + measureList.add(measure); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MemberSelectionReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MemberSelectionReader.java new file mode 100644 index 0000000..c926617 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MemberSelectionReader.java @@ -0,0 +1,162 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEmptyOrNullElementText; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.time.Instant; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.AfterPeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.BeforePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.LocalisedMemberValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.RangePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.SelectionValue; +import com.epam.jsdmx.infomodel.sdmx30.TimeRangePeriodImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class MemberSelectionReader { + + public MemberSelection getMemberSelection(XMLStreamReader reader) throws XMLStreamException { + var memberSelection = new MemberSelectionImpl(); + + memberSelection.setIncluded(XmlReaderUtils.getIncluded(reader)); + memberSelection.setRemovePrefix(XmlReaderUtils.getRemovePrefix(reader)); + memberSelection.setComponentId(XmlReaderUtils.getId(reader)); + + List selectionValues = getSelectionValues(reader); + memberSelection.setSelectionValues(selectionValues); + return memberSelection; + } + + public List getSelectionValues(XMLStreamReader reader) throws XMLStreamException { + List selectionValues = new ArrayList<>(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.COMPONENT, XmlConstants.KEY_VALUE)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.VALUE: + selectionValues.add(getValue(reader)); + break; + case XmlConstants.TIME_RANGE: + selectionValues.add(getTimeRange(reader)); + break; + default: + throw new IllegalArgumentException("MemberSelection " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + return selectionValues; + } + + private SelectionValue getTimeRange(XMLStreamReader reader) throws XMLStreamException { + String validTo = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VALID_TO); + String validFrom = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VALID_FROM); + var rangePeriod = new RangePeriodImpl(); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.TIME_RANGE)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.BEFORE_PERIOD: + var beforePeriod = new BeforePeriodImpl(); + setTimeRangePeriod(reader, beforePeriod, validTo, validFrom); + moveToNextTag(reader); + return beforePeriod; + case XmlConstants.AFTER_PERIOD: + var afterPeriod = new AfterPeriodImpl(); + setTimeRangePeriod(reader, afterPeriod, validTo, validFrom); + moveToNextTag(reader); + return afterPeriod; + case XmlConstants.START_PERIOD: + rangePeriod.setStartPeriod(getTimeRangePeriod(reader, validTo, validFrom)); + break; + case XmlConstants.END_PERIOD: + rangePeriod.setEndPeriod(getTimeRangePeriod(reader, validTo, validFrom)); + break; + default: + throw new IllegalArgumentException("TimeRange " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + rangePeriod.setValidFrom(parseDate(validFrom)); + rangePeriod.setValidTo(parseDate(validTo)); + return rangePeriod; + } + + private TimeRangePeriodImpl getTimeRangePeriod(XMLStreamReader reader, String validTo, String validFrom) throws XMLStreamException { + var timeRangePeriod = new TimeRangePeriodImpl(); + String isInclusive = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_INCLUSIVE); + if (isNotEmptyOrNullElementText(isInclusive)) { + timeRangePeriod.setInclusive(Boolean.parseBoolean(isInclusive)); + String period = reader.getElementText(); + if (isNotEmptyOrNullElementText(period)) { + timeRangePeriod.setPeriod(period); + } + timeRangePeriod.setValidTo(parseDate(validTo)); + timeRangePeriod.setValidFrom(parseDate(validFrom)); + } + return timeRangePeriod; + } + + private void setTimeRangePeriod(XMLStreamReader reader, TimeRangePeriodImpl beforePeriod, String validTo, String validFrom) throws XMLStreamException { + String isInclusive = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_INCLUSIVE); + if (isNotEmptyOrNullElementText(isInclusive)) { + beforePeriod.setInclusive(Boolean.parseBoolean(isInclusive)); + beforePeriod.setValidTo(parseDate(validTo)); + beforePeriod.setValidFrom(parseDate(validFrom)); + String period = reader.getElementText(); + if (isNotEmptyOrNullElementText(period)) { + beforePeriod.setPeriod(period); + } + } + } + + private SelectionValue getValue(XMLStreamReader reader) throws XMLStreamException { + var memberValue = new MemberValueImpl(); + var localisedMemberValue = new LocalisedMemberValueImpl(); + String validFrom = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VALID_FROM); + String validTo = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VALID_TO); + String cascadeValues = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.CASCADE_VALUES); + String local = reader.getAttributeValue(XmlConstants.XML_1998_NAMESPACE, XmlConstants.LANG); + memberValue.setCascadeValue(XmlConstants.STRING_CASCADE_VALUE_TYPE.get(cascadeValues)); + + if (isNotEmptyOrNullElementText(validTo)) { + memberValue.setValidTo(parseDate(validTo)); + localisedMemberValue.setValidTo(parseDate(validTo)); + } + + if (isNotEmptyOrNullElementText(validFrom)) { + memberValue.setValidFrom(parseDate(validFrom)); + localisedMemberValue.setValidFrom(parseDate(validFrom)); + } + + String value = reader.getElementText(); + memberValue.setValue(value); + localisedMemberValue.setValue(value); + + if (local != null) { + localisedMemberValue.setLocale(local); + return localisedMemberValue; + } + return memberValue; + } + + private Instant parseDate(String date) { + try { + return Instant.parse(date); + } catch (DateTimeParseException ex) { + return null; + } + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataConstraintReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataConstraintReader.java new file mode 100644 index 0000000..e814f64 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataConstraintReader.java @@ -0,0 +1,154 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setCommonAttributes; + +import java.net.URISyntaxException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.MetadataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataTargetRegion; +import com.epam.jsdmx.infomodel.sdmx30.MetadataTargetRegionImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class MetadataConstraintReader extends XmlReader { + + private final List constrainedArtefacts = new ArrayList<>(); + private final ReleaseCalendarReader releaseCalendarReader; + private final MemberSelectionReader memberSelectionReader; + List metadataTargetRegions = new ArrayList<>(); + + public MetadataConstraintReader(AnnotableReader annotableReader, + NameableReader nameableReader, + MemberSelectionReader memberSelectionReader, + ReleaseCalendarReader releaseCalendarReader) { + super(annotableReader, nameableReader); + this.memberSelectionReader = memberSelectionReader; + this.releaseCalendarReader = releaseCalendarReader; + } + + @Override + protected MetadataConstraintImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + MetadataConstraintImpl metadataConstraint = super.read(reader); + metadataConstraint.setConstrainedArtefacts(new ArrayList<>(constrainedArtefacts)); + metadataConstraint.setMetadataTargetRegions(new ArrayList<>(metadataTargetRegions)); + return metadataConstraint; + } + + @Override + protected void read(XMLStreamReader reader, MetadataConstraintImpl maintainableArtefact) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.CONSTRAINT_ATTACHMENT: + readConstraintsAttachments(reader); + break; + case XmlConstants.RELEASE_CALENDAR: + maintainableArtefact.setReleaseCalendar(releaseCalendarReader.getReleaseCalendar(reader)); + break; + case XmlConstants.METADATA_TARGET_REGION: + metadataTargetRegions.add(getMetadataTargetRegion(reader)); + break; + default: + throw new IllegalArgumentException("MetadataConstraint " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + } + + @Override + protected MetadataConstraintImpl createMaintainableArtefact() { + return new MetadataConstraintImpl(); + } + + private MetadataTargetRegion getMetadataTargetRegion(XMLStreamReader reader) throws XMLStreamException { + var metadataTargetRegion = new MetadataTargetRegionImpl(); + + List memberSelections = new ArrayList<>(); + metadataTargetRegion.setIncluded(XmlReaderUtils.getIncluded(reader)); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VALID_TO)) + .map(Instant::parse) + .ifPresent(metadataTargetRegion::setValidTo); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VALID_FROM)) + .map(Instant::parse) + .ifPresent(metadataTargetRegion::setValidFrom); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.METADATA_TARGET_REGION)) { + String localName = reader.getLocalName(); + if (!XmlConstants.COMPONENT.equals(localName)) { + throw new IllegalArgumentException("MetadataTargetRegion " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + memberSelections.add(memberSelectionReader.getMemberSelection(reader)); + + moveToNextTag(reader); + } + metadataTargetRegion.setMemberSelections(memberSelections); + return metadataTargetRegion; + } + + private void readConstraintsAttachments(XMLStreamReader reader) throws XMLStreamException { + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.CONSTRAINT_ATTACHMENT)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.METADATA_PROVIDER: + case XmlConstants.METADATA_SET: + case XmlConstants.METADATA_STRUCTURE: + case XmlConstants.METADATAFLOW: + case XmlConstants.METADATA_PROVISION_AGREEMENT: + addArtefactReference(reader); + break; + default: + throw new IllegalArgumentException("ConstraintsAttachments " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + } + + private void addArtefactReference(XMLStreamReader reader) throws XMLStreamException { + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(IdentifiableArtefactReferenceImpl::new) + .ifPresent(constrainedArtefacts::add); + } + + @Override + protected void setAttributes(XMLStreamReader reader, MetadataConstraintImpl maintainableArtefact) throws XMLStreamException { + setCommonAttributes(reader, maintainableArtefact); + } + + @Override + protected String getName() { + return XmlConstants.METADATA_CONSTRAINT; + } + + @Override + protected String getNames() { + return XmlConstants.METADATA_CONSTRAINTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getMetadataConstraints().addAll(artefacts); + } + + @Override + protected void clean() { + constrainedArtefacts.clear(); + metadataTargetRegions.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataProviderSchemeReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataProviderSchemeReader.java new file mode 100644 index 0000000..23029cf --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataProviderSchemeReader.java @@ -0,0 +1,100 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProvider; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class MetadataProviderSchemeReader extends XmlReader { + + private final OrganisationReader organisationReader; + + private final List dataProviders = new ArrayList<>(); + + public MetadataProviderSchemeReader(AnnotableReader annotableReader, + NameableReader nameableReader, + OrganisationReader organisationReader) { + super(annotableReader, nameableReader); + this.organisationReader = organisationReader; + } + + @Override + protected MetadataProviderSchemeImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + MetadataProviderSchemeImpl dataProviderScheme = super.read(reader); + dataProviderScheme.setItems(new ArrayList<>(dataProviders)); + return dataProviderScheme; + } + + @Override + protected void read(XMLStreamReader reader, MetadataProviderSchemeImpl maintainableArtefact) throws URISyntaxException, XMLStreamException { + String name = reader.getLocalName(); + if (!XmlConstants.METADATA_PROVIDER.equals(name)) { + throw new IllegalArgumentException("MetadataProviderScheme " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + MetadataProvider dataProvider = organisationReader.addOrganisation(reader, new MetadataProviderImpl(), null); + dataProviders.add(dataProvider); + } + + @Override + protected MetadataProviderSchemeImpl createMaintainableArtefact() { + return new MetadataProviderSchemeImpl(); + } + + @Override + protected void setAttributes(XMLStreamReader reader, MetadataProviderSchemeImpl artefact) throws XMLStreamException { + XmlReaderUtils.setUri(reader, artefact); + + XmlReaderUtils.setStructureUrl(reader, artefact); + + XmlReaderUtils.setServiceUrl(reader, artefact); + + artefact.setId(XmlConstants.METADATA_PROVIDERS); + + artefact.setVersion(Version.createFromString(XmlConstants.DEFAULT_VERSION)); + + XmlReaderUtils.setAgencyId(reader, artefact); + + XmlReaderUtils.setExternalReference(reader, artefact); + + XmlReaderUtils.setValidTo(reader, artefact); + + XmlReaderUtils.setValidFrom(reader, artefact); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_PARTIAL)) + .map(Boolean::parseBoolean) + .ifPresent(artefact::setPartial); + } + + @Override + protected String getName() { + return XmlConstants.METADATA_PROVIDER_SCHEME; + } + + @Override + protected String getNames() { + return XmlConstants.METADATA_PROVIDER_SCHEMES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getMetadataProviderSchemes().addAll(artefacts); + } + + @Override + protected void clean() { + dataProviders.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataProvisionAgreementReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataProvisionAgreementReader.java new file mode 100644 index 0000000..98952a8 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataProvisionAgreementReader.java @@ -0,0 +1,69 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setCommonAttributes; + +import java.net.URISyntaxException; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProvisionAgreementImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public class MetadataProvisionAgreementReader extends XmlReader { + + public MetadataProvisionAgreementReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @Override + protected MetadataProvisionAgreementImpl createMaintainableArtefact() { + return new MetadataProvisionAgreementImpl(); + } + + @Override + protected void read(XMLStreamReader reader, MetadataProvisionAgreementImpl metadataProvisionAgreement) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.METADATAFLOW: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(MaintainableArtefactReference::new) + .ifPresent(metadataProvisionAgreement::setControlledStructureUsage); + break; + case XmlConstants.METADATA_PROVIDER: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(MaintainableArtefactReference::new) + .ifPresent(metadataProvisionAgreement::setMetadataProvider); + break; + default: + throw new IllegalArgumentException("MetadataProvisionAgreement " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + } + + @Override + protected void setAttributes(XMLStreamReader reader, MetadataProvisionAgreementImpl maintainableArtefact) throws XMLStreamException { + setCommonAttributes(reader, maintainableArtefact); + } + + @Override + protected String getName() { + return XmlConstants.METADATA_PROVISION_AGREEMENT; + } + + @Override + protected String getNames() { + return XmlConstants.METADATA_PROVISION_AGREEMENTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getMetadataProvisionAgreements().addAll(artefacts); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataStructureDefinitionReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataStructureDefinitionReader.java new file mode 100644 index 0000000..bf08cc3 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataStructureDefinitionReader.java @@ -0,0 +1,171 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.readConceptIdentity; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setCommonAttributes; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttribute; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinitionImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +public class MetadataStructureDefinitionReader extends XmlReader { + + private final RepresentationReader representationReader; + + public MetadataStructureDefinitionReader(AnnotableReader annotableReader, + NameableReader nameableReader, + RepresentationReader representationReader) { + super(annotableReader, nameableReader); + this.representationReader = representationReader; + } + + @Override + protected MetadataStructureDefinitionImpl createMaintainableArtefact() { + return new MetadataStructureDefinitionImpl(); + } + + @Override + protected void read(XMLStreamReader reader, + MetadataStructureDefinitionImpl metadataStructureDefinition) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + if (!XmlConstants.METADATA_STRUCTURE_COMPONENTS.equals(localName)) { + throw new IllegalArgumentException("MetadataStructureDefinition " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + + var metadataAttributeDescriptor = new MetadataAttributeDescriptorImpl(); + setMetadataStructureComponents(reader, metadataAttributeDescriptor); + if (CollectionUtils.isNotEmpty(metadataAttributeDescriptor.getComponents())) { + metadataStructureDefinition.setAttributeDescriptor(metadataAttributeDescriptor); + } + } + + private void setMetadataStructureComponents(XMLStreamReader reader, + MetadataAttributeDescriptorImpl attributeDescriptor) throws XMLStreamException, URISyntaxException { + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.METADATA_STRUCTURE_COMPONENTS)) { + String name = reader.getLocalName(); + + if (!XmlConstants.METADATA_ATTRIBUTE_LIST.equals(name)) { + throw new IllegalArgumentException("MetadataStructureComponents " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + setMetadataAttributeList(reader, attributeDescriptor); + moveToNextTag(reader); + } + } + + private void setMetadataAttributeList(XMLStreamReader reader, + MetadataAttributeDescriptorImpl attributeDescriptor) throws URISyntaxException, XMLStreamException { + Optional.ofNullable(XmlReaderUtils.getId(reader)) + .ifPresent(attributeDescriptor::setId); + + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + attributeDescriptor.setUri(new URI(uri)); + } + + List metadataAttributeList = new ArrayList<>(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.METADATA_ATTRIBUTE_LIST)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, attributeDescriptor); + break; + case XmlConstants.METADATA_ATTRIBUTE: + MetadataAttributeImpl metadataAttribute = getMetadataAttribute(reader); + metadataAttributeList.add(metadataAttribute); + break; + default: + throw new IllegalArgumentException("MetadataAttributeList " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + attributeDescriptor.setComponents(metadataAttributeList); + } + + private MetadataAttributeImpl getMetadataAttribute(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + var metadataAttribute = new MetadataAttributeImpl(); + List hierarchy = new ArrayList<>(); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .ifPresent(metadataAttribute::setId); + + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + metadataAttribute.setUri(new URI(uri)); + } + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.MAX_OCCURS)) + .map(Integer::parseInt) + .ifPresent(metadataAttribute::setMaxOccurs); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.MIN_OCCURS)) + .map(Integer::parseInt) + .ifPresent(metadataAttribute::setMinOccurs); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_PRESENTATIONAL)) + .map(Boolean::parseBoolean) + .ifPresent(metadataAttribute::setPresentational); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.METADATA_ATTRIBUTE)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, metadataAttribute); + break; + case XmlConstants.CONCEPT_IDENTITY: + readConceptIdentity(reader, metadataAttribute); + break; + case XmlConstants.LOCAL_REPRESENTATION: + metadataAttribute.setLocalRepresentation(representationReader.readRepresentation(reader)); + break; + case XmlConstants.METADATA_ATTRIBUTE: + hierarchy.add(getMetadataAttribute(reader)); + break; + default: + throw new IllegalArgumentException("MetadataAttribute " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + metadataAttribute.setHierarchy(hierarchy); + return metadataAttribute; + } + + @Override + protected void setAttributes(XMLStreamReader reader, MetadataStructureDefinitionImpl maintainableArtefact) throws XMLStreamException { + setCommonAttributes(reader, maintainableArtefact); + } + + @Override + protected String getName() { + return XmlConstants.METADATA_STRUCTURE; + } + + @Override + protected String getNames() { + return XmlConstants.METADATA_STRUCTURES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getMetadataStructureDefinitions().addAll(artefacts); + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataflowReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataflowReader.java new file mode 100644 index 0000000..3101437 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/MetadataflowReader.java @@ -0,0 +1,87 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableObjectSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.MetadataflowImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public class MetadataflowReader extends XmlReader { + + private final List artefactReferences = new ArrayList<>(); + + public MetadataflowReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @Override + protected MetadataflowImpl createMaintainableArtefact() { + return new MetadataflowImpl(); + } + + @Override + protected MetadataflowImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + MetadataflowImpl metadataflow = super.read(reader); + var objectSelection = new IdentifiableObjectSelectionImpl(); + objectSelection.setResolvesTo(new ArrayList<>(artefactReferences)); + metadataflow.setSelections(List.of(objectSelection)); + return metadataflow; + } + + @Override + protected void read(XMLStreamReader reader, MetadataflowImpl metadataflow) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.STRUCTURE_UPPER: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(MaintainableArtefactReference::new) + .ifPresent(metadataflow::setStructure); + break; + case XmlConstants.TARGET: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(MaintainableArtefactReference::new) + .ifPresent(artefactReferences::add); + break; + default: + throw new IllegalArgumentException("Metadataflow " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + } + + @Override + protected String getName() { + return XmlConstants.METADATA_FLOW; + } + + @Override + protected String getNames() { + return XmlConstants.METADATA_FLOWS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getMetadataflows().addAll(artefacts); + } + + @Override + protected void setAttributes(XMLStreamReader reader, MetadataflowImpl metadataflow) { + XmlReaderUtils.setCommonAttributes(reader, metadataflow); + } + + @Override + protected void clean() { + artefactReferences.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/NameableReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/NameableReader.java new file mode 100644 index 0000000..c45550f --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/NameableReader.java @@ -0,0 +1,19 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.util.Map; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public class NameableReader { + + public void setNameable(XMLStreamReader reader, Map nameableMap) throws XMLStreamException { + String locale = reader.getAttributeValue(XmlConstants.XML_1998_NAMESPACE, XmlConstants.LANG); + String text = reader.getElementText(); + if (locale != null && text != null) { + nameableMap.put(locale, text); + } + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/OrganisationReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/OrganisationReader.java new file mode 100644 index 0000000..4e551ce --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/OrganisationReader.java @@ -0,0 +1,199 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Contact; +import com.epam.jsdmx.infomodel.sdmx30.ContactImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import lombok.AllArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +@AllArgsConstructor +public class OrganisationReader { + + private final AnnotableReader annotableReader; + private final NameableReader nameableReader; + + public > T addOrganisation(XMLStreamReader reader, + T organisation, + Map organisationWithParentId) throws URISyntaxException, XMLStreamException { + String parentId = null; + + Optional.ofNullable(XmlReaderUtils.getId(reader)) + .ifPresent(organisation::setId); + + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + organisation.setUri(new URI(uri)); + } + + Map names = new HashMap<>(); + Map descriptions = new HashMap<>(); + List contacts = new ArrayList<>(); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.DATA_CONSUMER, XmlConstants.AGENCY, + XmlConstants.DATA_PROVIDER, XmlConstants.METADATA_PROVIDER, XmlConstants.ORGANISATION_UNIT)) { + String name = reader.getLocalName(); + switch (name) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, organisation); + break; + case XmlConstants.COM_NAME: + nameableReader.setNameable(reader, names); + break; + case XmlConstants.COM_DESCRIPTION: + nameableReader.setNameable(reader, descriptions); + break; + case XmlConstants.CONTACT: + ContactImpl contact = getContact(reader); + contacts.add(contact); + break; + case XmlConstants.STRUCTURE_PARENT: + parentId = reader.getElementText(); + break; + default: + throw new IllegalArgumentException("Organisation " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + + } + moveToNextTag(reader); + } + organisation.setName(names.isEmpty() ? null : new InternationalString(names)); + organisation.setDescription(descriptions.isEmpty() ? null : new InternationalString(descriptions)); + organisation.setContacts(contacts); + if (organisationWithParentId != null) { + organisationWithParentId.put(organisation, parentId); + } + return organisation; + } + + private ContactImpl getContact(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + var contact = new ContactImpl(); + + Map roles = new HashMap<>(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.CONTACT)) { + String name = reader.getLocalName(); + switch (name) { + case XmlConstants.NAME: + String contactName = reader.getElementText(); + setContractName(contact, contactName); + break; + case XmlConstants.DEPARTMENT: + String department = reader.getElementText(); + setDepartment(contact, department); + break; + case XmlConstants.ROLE: + nameableReader.setNameable(reader, roles); + break; + case XmlConstants.TELEPHONE: + String telephone = reader.getElementText(); + setTelephone(contact, telephone); + break; + case XmlConstants.FAX: + String fax = reader.getElementText(); + setFax(contact, fax); + break; + case XmlConstants.X_400: + String x400 = reader.getElementText(); + setX400(contact, x400); + break; + case XmlConstants.URI: + String uri = reader.getElementText(); + setUri(contact, uri); + break; + case XmlConstants.EMAIL: + String email = reader.getElementText(); + setEmail(contact, email); + break; + default: + throw new IllegalArgumentException("Contact " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + moveToNextTag(reader); + } + contact.setResponsibility(roles.isEmpty() ? null : new InternationalString(roles)); + return contact; + } + + private void setFax(ContactImpl contact, String fax) { + if (XmlReaderUtils.isNotEmptyOrNullElementText(fax)) { + contact.setFax(fax); + } + } + + private void setX400(ContactImpl contact, String x400) { + if (XmlReaderUtils.isNotEmptyOrNullElementText(x400)) { + contact.setX400(x400); + } + } + + private void setUri(ContactImpl contact, String uri) throws URISyntaxException { + if (XmlReaderUtils.isNotEmptyOrNullElementText(uri)) { + contact.setUri(new URI(uri)); + } + } + + private void setEmail(ContactImpl contact, String email) { + if (XmlReaderUtils.isNotEmptyOrNullElementText(email)) { + contact.setEmail(email); + } + } + + private void setTelephone(ContactImpl contact, String telephone) { + if (XmlReaderUtils.isNotEmptyOrNullElementText(telephone)) { + contact.setTelephone(telephone); + } + } + + private void setDepartment(ContactImpl contact, String department) { + if (XmlReaderUtils.isNotEmptyOrNullElementText(department)) { + contact.setOrganizationUnit(department); + } + } + + private void setContractName(ContactImpl contact, String contactName) { + if (XmlReaderUtils.isNotEmptyOrNullElementText(contactName)) { + contact.setName(contactName); + } + } + + public > Map> formHierarchy(Map dataConsumerWithParent) { + Map> parentChildren = new HashMap<>(); + Set consumers = dataConsumerWithParent.keySet(); + Map consumerWithId = consumers.stream() + .collect(Collectors.toMap( + IdentifiableArtefactImpl::getId, + consumer -> consumer + )); + for (Map.Entry data : dataConsumerWithParent.entrySet()) { + String value = data.getValue(); + if (value != null) { + T dataConsumer = consumerWithId.get(value); + if (parentChildren.containsKey(dataConsumer)) { + parentChildren.get(dataConsumer).add(data.getKey()); + } else { + parentChildren.put(dataConsumer, List.of(data.getKey())); + } + } + } + return parentChildren; + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/OrganisationSchemeMapReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/OrganisationSchemeMapReader.java new file mode 100644 index 0000000..70392c2 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/OrganisationSchemeMapReader.java @@ -0,0 +1,86 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationSchemeMapImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public class OrganisationSchemeMapReader extends XmlReader implements ItemSchemeMapReader { + + private final List itemMaps = new ArrayList<>(); + + public OrganisationSchemeMapReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @Override + protected OrganisationSchemeMapImpl createMaintainableArtefact() { + return new OrganisationSchemeMapImpl(); + } + + @Override + protected OrganisationSchemeMapImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + OrganisationSchemeMapImpl organisationSchemeMap = super.read(reader); + organisationSchemeMap.setItemMaps(new ArrayList<>(itemMaps)); + return organisationSchemeMap; + } + + @Override + protected void read(XMLStreamReader reader, OrganisationSchemeMapImpl organisationSchemeMap) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.SOURCE: + Optional.ofNullable(reader.getElementText()) + .map(MaintainableArtefactReference::new) + .ifPresent(organisationSchemeMap::setSource); + break; + case XmlConstants.TARGET: + Optional.ofNullable(reader.getElementText()) + .map(MaintainableArtefactReference::new) + .ifPresent(organisationSchemeMap::setTarget); + break; + case XmlConstants.ITEM_MAP: + itemMaps.add(getItemMap(reader, annotableReader)); + break; + default: + throw new IllegalArgumentException("CategorySchemeMap " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + } + + @Override + protected void setAttributes(XMLStreamReader reader, OrganisationSchemeMapImpl maintainableArtefact) throws XMLStreamException { + XmlReaderUtils.setCommonAttributes(reader, maintainableArtefact); + } + + @Override + protected String getName() { + return XmlConstants.ORGANISATION_SCHEME_MAP; + } + + @Override + protected String getNames() { + return XmlConstants.ORGANISATION_SCHEME_MAPS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getOrganisationSchemeMaps().addAll(artefacts); + } + + + @Override + protected void clean() { + itemMaps.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/OrganisationUnitSchemeReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/OrganisationUnitSchemeReader.java new file mode 100644 index 0000000..565a5c0 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/OrganisationUnitSchemeReader.java @@ -0,0 +1,120 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setAgencyId; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setExternalReference; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setId; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setServiceUrl; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setStructureUrl; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setUri; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setValidFrom; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setValidTo; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnit; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitImpl; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +public class OrganisationUnitSchemeReader extends XmlReader { + + private final List organisationUnitList = new ArrayList<>(); + private final OrganisationReader organisationReader; + private final Map organisationUnitStringMap = new HashMap<>(); + + + public OrganisationUnitSchemeReader(AnnotableReader annotableReader, + NameableReader nameableReader, OrganisationReader organisationReader) { + super(annotableReader, nameableReader); + this.organisationReader = organisationReader; + } + + @Override + protected OrganisationUnitSchemeImpl createMaintainableArtefact() { + return new OrganisationUnitSchemeImpl(); + } + + @Override + protected OrganisationUnitSchemeImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + OrganisationUnitSchemeImpl organisationUnitScheme = super.read(reader); + if (CollectionUtils.isNotEmpty(organisationUnitList)) { + Map> organisationListMap = organisationReader.formHierarchy(organisationUnitStringMap); + for (Map.Entry> organisationHier : organisationListMap.entrySet()) { + List organisationUnitImplList = organisationHier.getValue(); + List hierarchy = new ArrayList<>(organisationUnitImplList); + organisationHier.getKey().setHierarchy(hierarchy); + } + } + organisationUnitScheme.setItems(new ArrayList<>(organisationUnitList)); + return organisationUnitScheme; + } + + @Override + protected void read(XMLStreamReader reader, OrganisationUnitSchemeImpl organisationUnitScheme) throws URISyntaxException, XMLStreamException { + String name = reader.getLocalName(); + if (!XmlConstants.ORGANISATION_UNIT.equals(name)) { + throw new IllegalArgumentException("OrganisationUnitScheme " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + OrganisationUnit organisationUnit = organisationReader.addOrganisation(reader, new OrganisationUnitImpl(), organisationUnitStringMap); + organisationUnitList.add(organisationUnit); + } + + @Override + protected void setAttributes(XMLStreamReader reader, OrganisationUnitSchemeImpl artefact) throws XMLStreamException { + setUri(reader, artefact); + + setStructureUrl(reader, artefact); + + setServiceUrl(reader, artefact); + + setId(reader, artefact); + + artefact.setVersion(Version.createFromString(XmlConstants.DEFAULT_VERSION)); + + setAgencyId(reader, artefact); + + setExternalReference(reader, artefact); + + setValidTo(reader, artefact); + + setValidFrom(reader, artefact); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_PARTIAL)) + .map(Boolean::parseBoolean) + .ifPresent(artefact::setPartial); + } + + @Override + protected String getName() { + return XmlConstants.ORGANISATION_UNIT_SCHEME; + } + + @Override + protected String getNames() { + return XmlConstants.ORGANISATION_UNIT_SCHEMES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getOrganisationUnitSchemes().addAll(artefacts); + } + + @Override + protected void clean() { + organisationUnitList.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ProcessReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ProcessReader.java new file mode 100644 index 0000000..24587b9 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ProcessReader.java @@ -0,0 +1,262 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEmptyOrNullElementText; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setCommonAttributes; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ComputationImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.ProcessArtefact; +import com.epam.jsdmx.infomodel.sdmx30.ProcessArtefactImpl; +import com.epam.jsdmx.infomodel.sdmx30.ProcessImpl; +import com.epam.jsdmx.infomodel.sdmx30.ProcessStep; +import com.epam.jsdmx.infomodel.sdmx30.ProcessStepImpl; +import com.epam.jsdmx.infomodel.sdmx30.Transition; +import com.epam.jsdmx.infomodel.sdmx30.TransitionImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class ProcessReader extends XmlReader { + + private final List processStepList = new ArrayList<>(); + + public ProcessReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @Override + protected ProcessImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + ProcessImpl process = super.read(reader); + process.setSteps(new ArrayList<>(processStepList)); + return process; + } + + @Override + protected void read(XMLStreamReader reader, ProcessImpl maintainableArtefact) throws URISyntaxException, XMLStreamException { + String name = reader.getLocalName(); + if (!XmlConstants.PROCESS_STEP.equals(name)) { + throw new IllegalArgumentException("Process " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + ProcessStepImpl processStep = addProcessStep(reader); + processStepList.add(processStep); + } + + + @Override + protected ProcessImpl createMaintainableArtefact() { + return new ProcessImpl(); + } + + private ProcessStepImpl addProcessStep(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + var processStep = new ProcessStepImpl(); + List inputs = new ArrayList<>(); + List outputs = new ArrayList<>(); + List children = new ArrayList<>(); + List transitions = new ArrayList<>(); + Map names = new HashMap<>(); + Map descriptions = new HashMap<>(); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(processStep::setId); + + String uriString = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (isNotEmptyOrNullElementText(uriString)) { + processStep.setUri(new URI(uriString)); + } + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.PROCESS_STEP)) { + String name = reader.getLocalName(); + switch (name) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, processStep); + break; + case XmlConstants.NAME: + nameableReader.setNameable(reader, names); + break; + case XmlConstants.DESCRIPTION: + nameableReader.setNameable(reader, descriptions); + break; + case XmlConstants.COMPUTATION: + processStep.setComputation(getComputation(reader)); + break; + case XmlConstants.INPUT: + inputs.add(getInputOutput(reader)); + break; + case XmlConstants.OUTPUT: + outputs.add(getInputOutput(reader)); + break; + case XmlConstants.TRANSITION: + transitions.add(getTransition(reader)); + break; + case XmlConstants.PROCESS_STEP: + children.add(addProcessStep(reader)); + break; + default: + throw new IllegalArgumentException("ProcessStep " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + moveToNextTag(reader); + } + processStep.setInputs(inputs); + processStep.setOutputs(outputs); + processStep.setChildren(children); + processStep.setTransitions(transitions); + processStep.setName(new InternationalString(names)); + processStep.setDescription(new InternationalString(descriptions)); + return processStep; + } + + private Transition getTransition(XMLStreamReader reader) throws URISyntaxException, XMLStreamException { + var transition = new TransitionImpl(); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(transition::setId); + + String uriString = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (isNotEmptyOrNullElementText(uriString)) { + transition.setUri(new URI(uriString)); + } + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.LOCAL_ID)) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(transition::setLocalId); + + Map conditions = new HashMap<>(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.TRANSITION)) { + String name = reader.getLocalName(); + switch (name) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, transition); + break; + case XmlConstants.TARGET_STEP: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(transition::setTargetProcessStep); + break; + case XmlConstants.CONDITION: + nameableReader.setNameable(reader, conditions); + break; + default: + throw new IllegalArgumentException("Transition " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + moveToNextTag(reader); + } + transition.setCondition(new InternationalString(conditions)); + return transition; + } + + private ProcessArtefact getInputOutput(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + var processArtefact = new ProcessArtefactImpl(); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.LOCAL_ID)) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(processArtefact::setLocalId); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.INPUT, XmlConstants.OUTPUT)) { + String name = reader.getLocalName(); + switch (name) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, processArtefact); + break; + case XmlConstants.OBJECT_REFERENCE: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(MaintainableArtefactReference::new) + .ifPresent(processArtefact::setArtefact); + break; + default: + throw new IllegalArgumentException("ProcessArtefact " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + moveToNextTag(reader); + } + return processArtefact; + } + + private ComputationImpl getComputation(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + var computation = new ComputationImpl(); + String localId = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.LOCAL_ID); + if (isNotEmptyOrNullElementText(localId)) { + computation.setLocalId(localId); + } + + String softwareLang = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.SOFTWARE_LANGUAGE); + if (isNotEmptyOrNullElementText(softwareLang)) { + computation.setSoftwareLanguage(softwareLang); + } + + String softwareVersion = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.SOFTWARE_VERSION); + if (isNotEmptyOrNullElementText(softwareLang)) { + computation.setSoftwareVersion(softwareVersion); + } + + String softwarePackage = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.SOFTWARE_PACKAGE); + if (isNotEmptyOrNullElementText(softwareLang)) { + computation.setSoftwarePackage(softwarePackage); + } + + Map descriptions = new HashMap<>(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.COMPUTATION)) { + String name = reader.getLocalName(); + switch (name) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, computation); + break; + case XmlConstants.DESCRIPTION: + nameableReader.setNameable(reader, descriptions); + break; + default: + throw new IllegalArgumentException("Computation " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + moveToNextTag(reader); + } + computation.setDescription(new InternationalString(descriptions)); + return computation; + } + + @Override + protected void setAttributes(XMLStreamReader reader, ProcessImpl maintainableArtefact) throws XMLStreamException { + setCommonAttributes(reader, maintainableArtefact); + } + + @Override + protected String getName() { + return XmlConstants.PROCESS; + } + + @Override + protected String getNames() { + return XmlConstants.PROCESSES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getProcesses().addAll(artefacts); + } + + @Override + protected void clean() { + processStepList.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ProvisionAgreementReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ProvisionAgreementReader.java new file mode 100644 index 0000000..d63c729 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ProvisionAgreementReader.java @@ -0,0 +1,70 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setCommonAttributes; + +import java.net.URISyntaxException; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.ProvisionAgreementImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public class ProvisionAgreementReader extends XmlReader { + + public ProvisionAgreementReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @Override + protected ProvisionAgreementImpl createMaintainableArtefact() { + return new ProvisionAgreementImpl(); + } + + @Override + protected void read(XMLStreamReader reader, ProvisionAgreementImpl provisionAgreement) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.DATAFLOW: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(MaintainableArtefactReference::new) + .ifPresent(provisionAgreement::setControlledStructureUsage); + break; + case XmlConstants.DATA_PROVIDER: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(IdentifiableArtefactReferenceImpl::new) + .ifPresent(provisionAgreement::setDataProvider); + break; + default: + throw new IllegalArgumentException("ProvisionAgreement " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + } + + @Override + protected void setAttributes(XMLStreamReader reader, ProvisionAgreementImpl maintainableArtefact) throws XMLStreamException { + setCommonAttributes(reader, maintainableArtefact); + } + + @Override + protected String getName() { + return XmlConstants.PROVISION_AGREEMENT; + } + + @Override + protected String getNames() { + return XmlConstants.PROVISION_AGREEMENTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getProvisionAgreements().addAll(artefacts); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ReleaseCalendarReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ReleaseCalendarReader.java new file mode 100644 index 0000000..d8c49f8 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ReleaseCalendarReader.java @@ -0,0 +1,44 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.util.Optional; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendarImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public class ReleaseCalendarReader { + + public ReleaseCalendarImpl getReleaseCalendar(XMLStreamReader reader) throws XMLStreamException { + var releaseCalendar = new ReleaseCalendarImpl(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.RELEASE_CALENDAR)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.PERIODICITY: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(releaseCalendar::setPeriodicity); + break; + case XmlConstants.OFFSET: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(releaseCalendar::setOffset); + break; + case XmlConstants.TOLERANCE: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(releaseCalendar::setTolerance); + break; + default: + throw new IllegalArgumentException("ReleaseCalendar " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + return releaseCalendar; + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyMapReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyMapReader.java new file mode 100644 index 0000000..82024e6 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyMapReader.java @@ -0,0 +1,87 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setCommonAttributes; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyMapImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +public class ReportingTaxonomyMapReader extends XmlReader implements ItemSchemeMapReader { + + private final List itemMaps = new ArrayList<>(); + + public ReportingTaxonomyMapReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @Override + protected ReportingTaxonomyMapImpl createMaintainableArtefact() { + return new ReportingTaxonomyMapImpl(); + } + + @Override + protected ReportingTaxonomyMapImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + ReportingTaxonomyMapImpl reportingTaxonomyMap = super.read(reader); + reportingTaxonomyMap.setItemMaps(new ArrayList<>(itemMaps)); + return reportingTaxonomyMap; + } + + @Override + protected void read(XMLStreamReader reader, ReportingTaxonomyMapImpl reportingTaxonomyMap) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.SOURCE: + Optional.ofNullable(reader.getElementText()) + .map(MaintainableArtefactReference::new) + .ifPresent(reportingTaxonomyMap::setSource); + break; + case XmlConstants.TARGET: + Optional.ofNullable(reader.getElementText()) + .map(MaintainableArtefactReference::new) + .ifPresent(reportingTaxonomyMap::setTarget); + break; + case XmlConstants.ITEM_MAP: + itemMaps.add(getItemMap(reader, annotableReader)); + break; + default: + throw new IllegalArgumentException("ReportingTaxonomyMap " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + } + + @Override + protected void setAttributes(XMLStreamReader reader, ReportingTaxonomyMapImpl maintainableArtefact) throws XMLStreamException { + setCommonAttributes(reader, maintainableArtefact); + } + + @Override + protected String getName() { + return XmlConstants.REPORTING_TAXONOMY_MAP; + } + + @Override + protected String getNames() { + return XmlConstants.REPORTING_TAXONOMY_MAPS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getReportingTaxonomyMaps().addAll(artefacts); + } + + @Override + protected void clean() { + itemMaps.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyReader.java new file mode 100644 index 0000000..7362d2e --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyReader.java @@ -0,0 +1,150 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEmptyOrNullElementText; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setCommonAttributes; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.ReportingCategory; +import com.epam.jsdmx.infomodel.sdmx30.ReportingCategoryImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class ReportingTaxonomyReader extends XmlReader { + + private final List reportingCategories = new ArrayList<>(); + + public ReportingTaxonomyReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @Override + protected ReportingTaxonomyImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + ReportingTaxonomyImpl reportingTaxonomy = super.read(reader); + reportingTaxonomy.setItems(new ArrayList<>(reportingCategories)); + return reportingTaxonomy; + } + + @Override + protected void read(XMLStreamReader reader, ReportingTaxonomyImpl maintainableArtefact) throws URISyntaxException, XMLStreamException { + readReportingCategories(reader); + } + + @Override + protected ReportingTaxonomyImpl createMaintainableArtefact() { + return new ReportingTaxonomyImpl(); + } + + private void readReportingCategories(XMLStreamReader reader) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + if (!XmlConstants.REPORTING_CATEGORY.equals(localName)) { + throw new IllegalArgumentException("ReportingTaxonomy " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + reportingCategories.add(getReportingCategory(reader)); + } + + private ReportingCategory getReportingCategory(XMLStreamReader reader) throws URISyntaxException, XMLStreamException { + var reportingCategory = new ReportingCategoryImpl(); + Map names = new HashMap<>(); + Map descriptions = new HashMap<>(); + + List flows = new ArrayList<>(); + List structures = new ArrayList<>(); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .ifPresent(reportingCategory::setId); + + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + reportingCategory.setUri(new URI(uri)); + } + List hierarchy = new ArrayList<>(); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.REPORTING_CATEGORY)) { + String name = reader.getLocalName(); + switch (name) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, reportingCategory); + break; + case XmlConstants.NAME: + nameableReader.setNameable(reader, names); + break; + case XmlConstants.DESCRIPTION: + nameableReader.setNameable(reader, descriptions); + break; + case XmlConstants.PROVISIONING_METADATA: + String flow = reader.getElementText(); + if (isNotEmptyOrNullElementText(flow)) { + flows.add(new MaintainableArtefactReference(flow)); + } + break; + case XmlConstants.STRUCTURAL_METADATA: + String structure = reader.getElementText(); + if (isNotEmptyOrNullElementText(structure)) { + structures.add(new MaintainableArtefactReference(structure)); + } + break; + case XmlConstants.REPORTING_CATEGORY: + hierarchy.add(getReportingCategory(reader)); + break; + default: + throw new IllegalArgumentException("ReportingCategory " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + moveToNextTag(reader); + } + reportingCategory.setFlows(flows); + reportingCategory.setStructures(structures); + reportingCategory.setName(new InternationalString(names)); + reportingCategory.setDescription(new InternationalString(descriptions)); + reportingCategory.setHierarchy(hierarchy); + return reportingCategory; + } + + @Override + protected void setAttributes(XMLStreamReader reader, ReportingTaxonomyImpl reportingTaxonomy) throws XMLStreamException { + setCommonAttributes(reader, reportingTaxonomy); + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_PARTIAL)) + .map(Boolean::parseBoolean) + .ifPresent(reportingTaxonomy::setPartial); + } + + @Override + protected String getName() { + return XmlConstants.REPORTING_TAXONOMY; + } + + @Override + protected String getNames() { + return XmlConstants.REPORTING_TAXONOMIES; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getReportingTaxonomies().addAll(artefacts); + } + + @Override + protected void clean() { + reportingCategories.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/RepresentationMapReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/RepresentationMapReader.java new file mode 100644 index 0000000..8e3033d --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/RepresentationMapReader.java @@ -0,0 +1,188 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setCommonAttributes; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueTypeRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.ListReferenceValueRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.MappedValue; +import com.epam.jsdmx.infomodel.sdmx30.MappedValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapping; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMappingImpl; +import com.epam.jsdmx.infomodel.sdmx30.TargetValue; +import com.epam.jsdmx.infomodel.sdmx30.TargetValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.ValueRepresentation; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class RepresentationMapReader extends XmlReader { + + private final List representationMappings = new ArrayList<>(); + private final List target = new ArrayList<>(); + private final List source = new ArrayList<>(); + + public RepresentationMapReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @Override + protected RepresentationMapImpl createMaintainableArtefact() { + return new RepresentationMapImpl(); + } + + @Override + protected void clean() { + this.target.clear(); + this.source.clear(); + this.representationMappings.clear(); + } + + @Override + protected void read(XMLStreamReader reader, RepresentationMapImpl representationMap) throws URISyntaxException, XMLStreamException { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.SOURCE_CODELIST: + addListReferenceValueRepresentation(reader, source); + break; + case XmlConstants.SOURCE_DATA_TYPE: + addFacetValueTypeRepresentation(reader, source); + break; + case XmlConstants.TARGET_CODELIST: + addListReferenceValueRepresentation(reader, target); + break; + case XmlConstants.TARGET_DATA_TYPE: + addFacetValueTypeRepresentation(reader, target); + break; + case XmlConstants.REPRESENTATION_MAPPING: + setRepresentationMapping(reader, representationMappings); + break; + default: + throw new IllegalArgumentException("RepresentationMap " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + + representationMap.setSource(List.copyOf(source)); + representationMap.setTarget(List.copyOf(target)); + representationMap.setRepresentationMappings(List.copyOf(representationMappings)); + } + + private void setRepresentationMapping(XMLStreamReader reader, + List representationMappings) throws XMLStreamException, URISyntaxException { + var representationMapping = new RepresentationMappingImpl(); + + representationMapping.setValidFrom(XmlReaderUtils.getDate(reader, XmlConstants.VALID_FROM)); + representationMapping.setValidTo(XmlReaderUtils.getDate(reader, XmlConstants.VALID_TO)); + + List targetValues = new ArrayList<>(); + List sourceValues = new ArrayList<>(); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.REPRESENTATION_MAPPING)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, representationMapping); + break; + case XmlConstants.SOURCE_VALUE: + addSourceValue(reader, sourceValues); + break; + case XmlConstants.TARGET_VALUE: + addTargetValue(reader, targetValues); + break; + default: + throw new IllegalArgumentException("RepresentationMapping " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + + representationMapping.setTargetValues(targetValues); + representationMapping.setSourceValues(sourceValues); + representationMappings.add(representationMapping); + } + + private void addSourceValue(XMLStreamReader reader, List sourceValues) throws XMLStreamException { + var mappedValue = new MappedValueImpl(); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_REG_EX)) + .map(Boolean::parseBoolean) + .ifPresent(mappedValue::setRegEx); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.START_INDEX)) + .map(Integer::parseInt) + .ifPresent(mappedValue::setStartIndex); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.END_INDEX)) + .map(Integer::parseInt) + .ifPresent(mappedValue::setEndIndex); + + Optional.ofNullable(reader.getElementText()) + .ifPresent(mappedValue::setValue); + + sourceValues.add(mappedValue); + } + + private void addTargetValue(XMLStreamReader reader, List targetValues) throws XMLStreamException { + var targetValue = new TargetValueImpl(); + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(targetValue::setValue); + + targetValues.add(targetValue); + } + + private void addFacetValueTypeRepresentation(XMLStreamReader reader, List valueRepresentations) throws XMLStreamException { + var valueTypeRepresentation = new FacetValueTypeRepresentationImpl(); + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(FacetValueType::fromValue) + .ifPresent(valueTypeRepresentation::setType); + + valueRepresentations.add(valueTypeRepresentation); + } + + private void addListReferenceValueRepresentation(XMLStreamReader reader, List valueRepresentations) throws XMLStreamException { + var listReferenceValueRepresentation = new ListReferenceValueRepresentationImpl(); + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(MaintainableArtefactReference::new) + .ifPresent(listReferenceValueRepresentation::setReference); + + valueRepresentations.add(listReferenceValueRepresentation); + } + + @Override + protected void setAttributes(XMLStreamReader reader, RepresentationMapImpl maintainableArtefact) { + setCommonAttributes(reader, maintainableArtefact); + } + + @Override + protected String getName() { + return XmlConstants.REPRESENTATION_MAP; + } + + @Override + protected String getNames() { + return XmlConstants.REPRESENTATION_MAPS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getRepresentationMaps().addAll(artefacts); + } + +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/RepresentationReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/RepresentationReader.java new file mode 100644 index 0000000..a93445e --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/RepresentationReader.java @@ -0,0 +1,140 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.BaseFacetImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseTextFormatRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.EnumeratedRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.Facet; +import com.epam.jsdmx.infomodel.sdmx30.FacetType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.infomodel.sdmx30.SentinelValue; +import com.epam.jsdmx.infomodel.sdmx30.SentinelValueImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +@AllArgsConstructor +public class RepresentationReader { + + private final NameableReader nameableReader; + + public Representation readRepresentation(XMLStreamReader reader) throws XMLStreamException { + moveToNextTag(reader); + Representation representation = null; + while (isNotEndingTag(reader, XmlConstants.CORE_REPRESENTATION, XmlConstants.LOCAL_REPRESENTATION)) { + String name = reader.getLocalName(); + + switch (name) { + case XmlConstants.ENUMERATION: + String artefactReference = reader.getElementText(); + if (XmlReaderUtils.isNotEmptyOrNullElementText(artefactReference)) { + representation = new EnumeratedRepresentationImpl( + new MaintainableArtefactReference(artefactReference)); + } + moveToNextTag(reader); + break; + case XmlConstants.TEXT_FORMAT: + representation = readTextFormat(reader); + break; + case XmlConstants.ENUMERATION_FORMAT: + moveToNextTag(reader); + break; + default: + throw new IllegalArgumentException("Representation " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + } + return representation; + } + + public Representation readTextFormat(XMLStreamReader reader) throws XMLStreamException { + Set facets = new HashSet<>(); + if (reader.getAttributeCount() > 0) { + for (int index = 0; index < reader.getAttributeCount(); index++) { + readFacets(reader, facets, index); + } + } + + List sentinelValues = new ArrayList<>(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.TEXT_FORMAT)) { + String name = reader.getLocalName(); + var sentinelValue = new SentinelValueImpl(); + if (XmlConstants.SENTINEL_VALUE.equals(name)) { + String value = reader.getAttributeValue(StringUtils.EMPTY, "value"); + sentinelValue.setValue(value); + readSentinelElements(reader, sentinelValue); + sentinelValues.add(sentinelValue); + } + moveToNextTag(reader); + } + if (CollectionUtils.isNotEmpty(sentinelValues)) { + var baseFacet = new BaseFacetImpl(); + baseFacet.setSentinelValues(sentinelValues); + facets.add(baseFacet); + } + + moveToNextTag(reader); + return new BaseTextFormatRepresentationImpl(facets); + } + + private void readFacets(XMLStreamReader reader, Set facets, int index) { + QName format = reader.getAttributeName(index); + String txtFormat = format.getLocalPart(); + String formatValue = reader.getAttributeValue(StringUtils.EMPTY, txtFormat); + + if (XmlConstants.TEXT_TYPE.equals(txtFormat)) { + if (formatValue != null) { + var facet = new BaseFacetImpl(); + facet.setValueType(FacetValueType.fromValue(formatValue)); + facets.add(facet); + } + } else { + var facet = new BaseFacetImpl(); + facet.setType(FacetType.valueOf(XmlConstants.MAP_CODING_FORMAT.get(txtFormat))); + facet.setValue(formatValue); + facets.add(facet); + } + } + + public void readSentinelElements(XMLStreamReader reader, SentinelValueImpl sentinelValue) throws XMLStreamException { + Map names = new HashMap<>(); + Map descriptions = new HashMap<>(); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.SENTINEL_VALUE)) { + String name = reader.getLocalName(); + switch (name) { + case XmlConstants.COM_NAME: + nameableReader.setNameable(reader, names); + break; + case XmlConstants.COM_DESCRIPTION: + nameableReader.setNameable(reader, descriptions); + break; + default: + throw new IllegalArgumentException("SentinelValue " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + name); + } + moveToNextTag(reader); + } + sentinelValue.setName(new InternationalString(names)); + sentinelValue.setDescription(new InternationalString(descriptions)); + } + +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/StructureMapReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/StructureMapReader.java new file mode 100644 index 0000000..64ad0c3 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/StructureMapReader.java @@ -0,0 +1,423 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.net.URI; +import java.net.URISyntaxException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ComponentMap; +import com.epam.jsdmx.infomodel.sdmx30.ComponentMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.DateMap; +import com.epam.jsdmx.infomodel.sdmx30.DateMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.DatePatternMap; +import com.epam.jsdmx.infomodel.sdmx30.DatePatternMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.EpochMap; +import com.epam.jsdmx.infomodel.sdmx30.EpochMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.FixedValueMap; +import com.epam.jsdmx.infomodel.sdmx30.FixedValueMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.FrequencyFormatMapping; +import com.epam.jsdmx.infomodel.sdmx30.FrequencyFormatMappingImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.MappingRoleType; +import com.epam.jsdmx.infomodel.sdmx30.StructureMapImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +public class StructureMapReader extends XmlReader { + + private final List componentMaps = new ArrayList<>(); + + private final HashMap mappedComponentsDatePattern = new HashMap<>(); + private final HashMap mappedComponentsEpoch = new HashMap<>(); + private final Map> epochMapIdWithFrequencyIds = new HashMap<>(); + private final Map> datePatternMapIdWithFrequencyIds = new HashMap<>(); + List epochMaps = new ArrayList<>(); + List datePatternMaps = new ArrayList<>(); + List frequencyFormatMappings = new ArrayList<>(); + + public StructureMapReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + private static void addSource(XMLStreamReader reader, List sources) throws XMLStreamException { + Optional.ofNullable(reader.getElementText()) + .ifPresent(sources::add); + } + + @Override + protected StructureMapImpl createMaintainableArtefact() { + return new StructureMapImpl(); + } + + @Override + protected StructureMapImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + StructureMapImpl structureMap = super.read(reader); + setFrequencyFormatting(); + structureMap.setEpochMaps(CollectionUtils.isNotEmpty(epochMaps) ? new ArrayList<>(epochMaps) : null); + structureMap.setDatePatternMaps(CollectionUtils.isNotEmpty(datePatternMaps) ? new ArrayList<>(datePatternMaps) : null); + + setComponentMaps(structureMap); + return structureMap; + } + + @Override + protected void read(XMLStreamReader reader, StructureMapImpl structureMap) throws URISyntaxException, XMLStreamException { + List fixedValueMaps = new ArrayList<>(); + + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.SOURCE: + Optional.ofNullable(reader.getElementText()) + .map(MaintainableArtefactReference::new) + .ifPresent(structureMap::setSource); + break; + case XmlConstants.TARGET: + Optional.ofNullable(reader.getElementText()) + .map(MaintainableArtefactReference::new) + .ifPresent(structureMap::setTarget); + break; + case XmlConstants.EPOCH_MAP: + setEpochMap(reader, epochMaps); + break; + case XmlConstants.DATE_PATTERN_MAP: + setDatePatternMap(reader, datePatternMaps); + break; + case XmlConstants.FREQUENCY_FORMAT_MAPPING: + readFrequencyFormatMapping(reader, frequencyFormatMappings); + break; + case XmlConstants.COMPONENT_MAP: + addComponentMaps(reader, componentMaps); + break; + case XmlConstants.FIXED_VALUE_MAP: + setFixedValueMap(reader, fixedValueMaps); + break; + default: + throw new IllegalArgumentException("StructureMap " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + structureMap.setFixedComponentMaps(CollectionUtils.isNotEmpty(fixedValueMaps) ? fixedValueMaps : null); + } + + @Override + protected String getName() { + return XmlConstants.STRUCTURE_MAP; + } + + @Override + protected String getNames() { + return XmlConstants.STRUCTURE_MAPS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getStructureMaps().addAll(artefacts); + } + + private void setComponentMaps(StructureMapImpl structureMap) { + List componentMapsDatePattern = StructureMapUtils.extractComponentMapFromDatePatternMap(mappedComponentsDatePattern, structureMap); + List componentMapsEpoch = StructureMapUtils.extractComponentMapFromEpochMap(mappedComponentsEpoch, structureMap); + + List allComponentMaps = Stream.of(componentMapsDatePattern, componentMapsEpoch, componentMaps) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + structureMap.setComponentMaps(allComponentMaps); + } + + private void setFrequencyFormatting() { + if (CollectionUtils.isNotEmpty(frequencyFormatMappings)) { + + for (Map.Entry> epochMap : epochMapIdWithFrequencyIds.entrySet()) { + List epochFrequencies = frequencyFormatMappings.stream() + .filter(freq -> epochMap.getValue().contains(freq.getId())) + .collect(Collectors.toList()); + Optional optionalEpochMap = epochMaps.stream().filter(epoch -> epoch.equals(epochMap.getKey())) + .findFirst(); + optionalEpochMap.ifPresent(map -> ((EpochMapImpl) map).setMappedFrequencies(epochFrequencies)); + } + + for (Map.Entry> datePattern : datePatternMapIdWithFrequencyIds.entrySet()) { + List datePatternFrequencies = frequencyFormatMappings.stream() + .filter(freq -> datePattern.getValue().contains(freq.getId())) + .collect(Collectors.toList()); + Optional optionalDatePatternMap = datePatternMaps.stream().filter(patternMap -> patternMap.equals(datePattern.getKey())) + .findFirst(); + optionalDatePatternMap.ifPresent(map -> ((DatePatternMapImpl) map).setMappedFrequencies(datePatternFrequencies)); + } + } + } + + private void setFixedValueMap(XMLStreamReader reader, List fixedValueMaps) throws XMLStreamException, URISyntaxException { + var fixedValueMap = new FixedValueMapImpl(); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.FIXED_VALUE_MAP)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, fixedValueMap); + break; + case XmlConstants.SOURCE: + Optional.ofNullable(reader.getElementText()) + .ifPresent(source -> { + fixedValueMap.setRole(MappingRoleType.SOURCE); + fixedValueMap.setComponent(source); + }); + break; + case XmlConstants.TARGET: + Optional.ofNullable(reader.getElementText()) + .ifPresent(target -> { + fixedValueMap.setRole(MappingRoleType.TARGET); + fixedValueMap.setComponent(target); + }); + break; + case XmlConstants.VALUE: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .ifPresent(fixedValueMap::setValue); + break; + default: + throw new IllegalArgumentException("FixedValueMap " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + fixedValueMaps.add(fixedValueMap); + } + + private void addComponentMaps(XMLStreamReader reader, List componentMaps) throws XMLStreamException, URISyntaxException { + var componentMap = new ComponentMapImpl(); + List sources = new ArrayList<>(); + List targets = new ArrayList<>(); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.COMPONENT_MAP)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, componentMap); + break; + case XmlConstants.SOURCE: + Optional.ofNullable(reader.getElementText()) + .ifPresent(sources::add); + break; + case XmlConstants.TARGET: + Optional.ofNullable(reader.getElementText()) + .ifPresent(targets::add); + break; + case XmlConstants.REPRESENTATION_MAP: + Optional.ofNullable(reader.getElementText()) + .filter(XmlReaderUtils::isNotEmptyOrNullElementText) + .map(MaintainableArtefactReference::new) + .ifPresent(componentMap::setRepresentationMap); + break; + default: + throw new IllegalArgumentException("ComponentMap " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + componentMap.setSource(CollectionUtils.isNotEmpty(sources) ? sources : null); + componentMap.setTarget(CollectionUtils.isNotEmpty(targets) ? targets : null); + componentMaps.add(componentMap); + } + + private void readFrequencyFormatMapping(XMLStreamReader reader, + List frequencyFormatMappings) throws XMLStreamException, URISyntaxException { + var frequencyFormatMapping = new FrequencyFormatMappingImpl(); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .ifPresent(frequencyFormatMapping::setId); + + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + frequencyFormatMapping.setUri(new URI(uri)); + } + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.FREQUENCY_FORMAT_MAPPING)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, frequencyFormatMapping); + break; + case XmlConstants.FREQUENCY_ID: + String freqId = reader.getElementText(); + if (XmlReaderUtils.isNotEmptyOrNullElementText(freqId)) { + frequencyFormatMapping.setFrequencyCode(freqId); + } + break; + case XmlConstants.DATE_PATTERN: + String datePattern = reader.getElementText(); + if (XmlReaderUtils.isNotEmptyOrNullElementText(datePattern)) { + frequencyFormatMapping.setDatePattern(datePattern); + } + break; + default: + throw new IllegalArgumentException("FrequencyFormatMapping " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + frequencyFormatMappings.add(frequencyFormatMapping); + } + + private void setDatePatternMap(XMLStreamReader reader, List datePatternMaps) throws URISyntaxException, XMLStreamException { + var datePatternMap = new DatePatternMapImpl(); + readDateMapAttributes(reader, datePatternMap); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.SOURCE_PATTERN)) + .ifPresent(datePatternMap::setSourcePattern); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.LOCALE)) + .ifPresent(datePatternMap::setLocale); + + setDateMapComponents(reader, datePatternMap, datePatternMapIdWithFrequencyIds, mappedComponentsDatePattern); + datePatternMaps.add(datePatternMap); + } + + private void setEpochMap(XMLStreamReader reader, List epochMaps) throws URISyntaxException, XMLStreamException { + var epochMap = new EpochMapImpl(); + readDateMapAttributes(reader, epochMap); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.BASE_PERIOD)) + .map(Instant::parse) + .ifPresent(epochMap::setBasePeriod); + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.EPOCH_PERIOD)) + .map(XmlConstants.STRING_EPOCH_PERIOD_MAP::get) + .ifPresent(epochMap::setEpochPeriod); + + setDateMapComponents(reader, epochMap, epochMapIdWithFrequencyIds, mappedComponentsEpoch); + epochMaps.add(epochMap); + } + + private void setDateMapComponents(XMLStreamReader reader, DateMapImpl dateMap, + Map> dateMapWithFreqIds, + HashMap mappedComponentsWithDateMap + ) throws XMLStreamException, URISyntaxException { + List sources = new ArrayList<>(); + List targets = new ArrayList<>(); + List mappedFrequencyIds = new ArrayList<>(); + + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.EPOCH_MAP, XmlConstants.DATE_PATTERN_MAP)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, dateMap); + break; + case XmlConstants.SOURCE: + addSource(reader, sources); + break; + case XmlConstants.TARGET: + Optional.ofNullable(reader.getElementText()) + .ifPresent(targets::add); + break; + case XmlConstants.FREQUENCY_DIMENSION: + setFreqDimension(reader, dateMap); + break; + case XmlConstants.MAPPED_FREQUENCIES: + Optional.ofNullable(reader.getElementText()) + .ifPresent(mappedFrequencyIds::add); + break; + case XmlConstants.TARGET_FREQUENCY_ID: + setTargetFrequency(reader, dateMap); + break; + default: + throw new IllegalArgumentException("EpochMap " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + dateMapWithFreqIds.put(dateMap, mappedFrequencyIds); + List mComponents = new ArrayList<>(getMappedComponents(sources, targets)); + if (CollectionUtils.isNotEmpty(mComponents)) { + mappedComponentsWithDateMap.put(dateMap, mComponents.get(0)); + } + } + + private void setTargetFrequency(XMLStreamReader reader, DateMapImpl dateMap) throws XMLStreamException { + Optional.ofNullable(reader.getElementText()) + .ifPresent(dateMap::setTargetFrequencyId); + } + + private void setFreqDimension(XMLStreamReader reader, DateMapImpl dateMap) throws XMLStreamException { + Optional.ofNullable(reader.getElementText()) + .ifPresent(dateMap::setFrequencyDimension); + } + + private List getMappedComponents(List sources, List targets) { + List mappedComp = new ArrayList<>(); + int sourcesSize = sources.size(); + int targetsSize = targets.size(); + int minimumSize = Math.min(sourcesSize, targetsSize); + for (int i = 0; i < minimumSize; i++) { + var mappedComponent = new MappedComponent(); + mappedComponent.setTarget(targets.get(i)); + mappedComponent.setSource(sources.get(i)); + mappedComp.add(mappedComponent); + } + if (sourcesSize > minimumSize) { + for (int i = minimumSize + 1; i < sourcesSize; i++) { + var mappedComponent = new MappedComponent(); + mappedComponent.setSource(sources.get(i)); + mappedComp.add(mappedComponent); + } + } + + if (targets.size() > minimumSize) { + for (int i = minimumSize + 1; i < targetsSize; i++) { + var mappedComponent = new MappedComponent(); + mappedComponent.setTarget(targets.get(i)); + mappedComp.add(mappedComponent); + } + } + + return CollectionUtils.isNotEmpty(mappedComp) ? mappedComp : Collections.emptyList(); + } + + private void readDateMapAttributes(XMLStreamReader reader, DateMapImpl epochMap) throws URISyntaxException { + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .ifPresent(epochMap::setId); + + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + epochMap.setUri(new URI(uri)); + } + + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.RESOLVE_PERIOD)) + .map(XmlConstants.STRING_RESOLVE_PERIOD_MAP::get) + .ifPresent(epochMap::setResolvePeriod); + } + + @Override + protected void setAttributes(XMLStreamReader reader, StructureMapImpl maintainableArtefact) throws XMLStreamException { + XmlReaderUtils.setCommonAttributes(reader, maintainableArtefact); + } + + @Override + protected void clean() { + componentMaps.clear(); + mappedComponentsDatePattern.clear(); + mappedComponentsEpoch.clear(); + epochMaps.clear(); + datePatternMaps.clear(); + frequencyFormatMappings.clear(); + epochMapIdWithFrequencyIds.clear(); + datePatternMapIdWithFrequencyIds.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/StructureMapUtils.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/StructureMapUtils.java new file mode 100644 index 0000000..59ac6ce --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/StructureMapUtils.java @@ -0,0 +1,143 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.epam.jsdmx.infomodel.sdmx30.ComponentMap; +import com.epam.jsdmx.infomodel.sdmx30.ComponentMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.DateMap; +import com.epam.jsdmx.infomodel.sdmx30.DatePatternMap; +import com.epam.jsdmx.infomodel.sdmx30.EpochMap; +import com.epam.jsdmx.infomodel.sdmx30.FrequencyFormatMapping; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureMap; +import com.epam.jsdmx.infomodel.sdmx30.StructureMapImpl; + +import org.apache.commons.collections.CollectionUtils; + +public final class StructureMapUtils { + + private StructureMapUtils() { + } + + public static Map> getEpochWithMappedComponent(List epochMaps, List componentMaps) { + Map epochs = epochMaps.stream() + .collect(Collectors.toMap(EpochMap::getId, Function.identity())); + if (CollectionUtils.isNotEmpty(componentMaps)) { + return componentMaps.stream() + .filter(Objects::nonNull) + .filter(componentMap -> componentMap.getRepresentationMap() != null) + .filter(componentMap -> epochs.containsKey(componentMap.getRepresentationMap() + .getItemId())) + .collect(Collectors.groupingBy(componentMap -> epochs.get(componentMap.getRepresentationMap() + .getItemId()), Collectors.mapping(map -> new MappedComponent(map.getSource() + .get(0), map.getTarget() + .get(0)), Collectors.toList()))); + } + return Collections.emptyMap(); + } + + public static Map> getDatePatternWithMappedComponent(List dateMap, List componentMaps) { + Map datePatterns = dateMap.stream() + .filter(datePatternMap -> datePatternMap.getId() != null) + .collect(Collectors.toMap(DatePatternMap::getId, Function.identity())); + if (CollectionUtils.isNotEmpty(componentMaps)) { + return componentMaps.stream() + .filter(Objects::nonNull) + .filter(componentMap -> componentMap.getRepresentationMap() != null) + .filter(componentMap -> datePatterns.containsKey(componentMap.getRepresentationMap() + .getItemId())) + .collect(Collectors.groupingBy(componentMap -> datePatterns.get(componentMap.getRepresentationMap() + .getItemId()), Collectors.mapping(map -> new MappedComponent(map.getSource() + .get(0), map.getTarget() + .get(0)), Collectors.toList()))); + } + return Collections.emptyMap(); + } + + public static List getFrequencyFormatMappings(List epochMaps, List datePatternMaps) { + List frequencyFormatMappings = new ArrayList<>(); + for (EpochMap epochMap : epochMaps) { + if (epochMap != null && epochMap.getMappedFrequencies() != null) { + frequencyFormatMappings.addAll(epochMap.getMappedFrequencies()); + } + } + for (DatePatternMap datePatternMap : datePatternMaps) { + if (datePatternMap != null && datePatternMap.getMappedFrequencies() != null) { + frequencyFormatMappings.addAll(datePatternMap.getMappedFrequencies()); + } + } + return frequencyFormatMappings; + } + + public static List getRepresentationMap(StructureMap structureMap) { + List epochIds = structureMap.getEpochMaps() + .stream() + .map(EpochMap::getId) + .collect(Collectors.toList()); + List datePatternIds = structureMap.getDatePatternMaps() + .stream() + .map(DatePatternMap::getId) + .collect(Collectors.toList()); + List nonRepresentationMapIds = Stream.concat(epochIds.stream(), datePatternIds.stream()) + .collect(Collectors.toList()); + List componentMaps = structureMap.getComponentMaps(); + return componentMaps == null ? null + : componentMaps.stream() + .filter(Objects::nonNull) + .filter(componentMap -> + componentMap.getRepresentationMap() == null + || !nonRepresentationMapIds.contains(componentMap.getRepresentationMap().getItemId())) + .collect(Collectors.toList()); + } + + public static List extractComponentMapFromDatePatternMap(Map mappedComponents, + StructureMapImpl structureMap) { + List componentMaps = new ArrayList<>(); + for (Map.Entry entrySet : mappedComponents + .entrySet()) { + ComponentMapImpl componentMapDP = new ComponentMapImpl(); + componentMapDP.setSource(List.of(entrySet.getValue() + .getSource())); + componentMapDP.setTarget(List.of(entrySet.getValue() + .getTarget())); + componentMapDP.setRepresentationMap( + new IdentifiableArtefactReferenceImpl(structureMap.getId(), structureMap.getOrganizationId(), structureMap.getVersion().toString(), + StructureClassImpl.DATE_PATTERN_MAP, entrySet.getKey() + .getId() + )); + componentMaps.add(componentMapDP); + } + return componentMaps; + } + + public static List extractComponentMapFromEpochMap(Map mappedComponents, StructureMapImpl structureMap) { + List componentMaps = new ArrayList<>(); + for (Map.Entry entrySet : mappedComponents + .entrySet()) { + ComponentMapImpl componentMapEpoch = new ComponentMapImpl(); + componentMapEpoch.setSource(List.of(entrySet.getValue() + .getSource())); + componentMapEpoch.setTarget(List.of(entrySet.getValue() + .getTarget())); + componentMapEpoch.setRepresentationMap( + new IdentifiableArtefactReferenceImpl( + structureMap.getId(), + structureMap.getOrganizationId(), + structureMap.getVersion().toString(), + StructureClassImpl.EPOCH_MAP, + entrySet.getKey() + .getId() + )); + componentMaps.add(componentMapEpoch); + } + return componentMaps; + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ValueListReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ValueListReader.java new file mode 100644 index 0000000..897d274 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/ValueListReader.java @@ -0,0 +1,113 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.setCommonAttributes; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.ValueItem; +import com.epam.jsdmx.infomodel.sdmx30.ValueItemImpl; +import com.epam.jsdmx.infomodel.sdmx30.ValueListImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import org.apache.commons.lang3.StringUtils; + +public class ValueListReader extends XmlReader { + + private List valueItems; + + public ValueListReader(AnnotableReader annotableReader, + NameableReader nameableReader) { + super(annotableReader, nameableReader); + } + + @Override + protected ValueListImpl read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + ValueListImpl valueList = super.read(reader); + valueList.setItems(new ArrayList<>(valueItems)); + return valueList; + } + + @Override + protected void read(XMLStreamReader reader, ValueListImpl maintainableArtefact) throws URISyntaxException, XMLStreamException { + var valueItem = new ValueItemImpl(); + String localName = reader.getLocalName(); + valueItems = new ArrayList<>(); + if (!XmlConstants.VALUE_ITEM.equals(localName)) { + throw new IllegalArgumentException("ValueList " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + + readValueItem(reader, valueItem); + } + + @Override + protected ValueListImpl createMaintainableArtefact() { + return new ValueListImpl(); + } + + private void readValueItem(XMLStreamReader reader, ValueItemImpl valueItem) throws XMLStreamException, URISyntaxException { + Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID)) + .ifPresent(valueItem::setId); + + Map names = new HashMap<>(); + Map descriptions = new HashMap<>(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.VALUE_ITEM)) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, valueItem); + break; + case XmlConstants.COM_NAME: + nameableReader.setNameable(reader, names); + break; + case XmlConstants.COM_DESCRIPTION: + nameableReader.setNameable(reader, descriptions); + break; + default: + throw new IllegalArgumentException("ValueItem " + XmlConstants.DOES_NOT_SUPPORT_ELEMENT + localName); + } + moveToNextTag(reader); + } + valueItem.setName(new InternationalString(names)); + valueItem.setDescription(new InternationalString(descriptions)); + valueItems.add(valueItem); + } + + @Override + protected void setAttributes(XMLStreamReader reader, ValueListImpl maintainableArtefact) throws XMLStreamException { + setCommonAttributes(reader, maintainableArtefact); + } + + @Override + protected String getName() { + return XmlConstants.VALUE_LIST; + } + + @Override + protected String getNames() { + return XmlConstants.VALUE_LISTS; + } + + @Override + protected void setArtefacts(Artefacts artefact, Set artefacts) { + artefact.getValueLists().addAll(artefacts); + } + + @Override + protected void clean() { + valueItems.clear(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlReader.java new file mode 100644 index 0000000..961aab5 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlReader.java @@ -0,0 +1,75 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactImpl; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public abstract class XmlReader { + + protected final AnnotableReader annotableReader; + protected final NameableReader nameableReader; + + protected abstract T createMaintainableArtefact(); + + protected abstract void read(XMLStreamReader reader, T maintainableArtefact) throws URISyntaxException, XMLStreamException; + + protected T read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + T maintainable = createMaintainableArtefact(); + setAttributes(reader, maintainable); + Map names = new HashMap<>(); + Map descriptions = new HashMap<>(); + + moveToNextTag(reader); + while (isNotEndingTag(reader, getName())) { + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.COM_ANNOTATIONS: + annotableReader.setAnnotations(reader, maintainable); + break; + case XmlConstants.COM_NAME: + nameableReader.setNameable(reader, names); + break; + case XmlConstants.COM_DESCRIPTION: + nameableReader.setNameable(reader, descriptions); + break; + case XmlConstants.COM_LINK: + moveToNextTag(reader); + break; + default: + read(reader, maintainable); + } + moveToNextTag(reader); + } + maintainable.setName(names.isEmpty() ? null : new InternationalString(names)); + maintainable.setDescription(descriptions.isEmpty() ? null : new InternationalString(descriptions)); + return maintainable; + } + + protected abstract void setAttributes(XMLStreamReader reader, T maintainableArtefact) throws XMLStreamException; + + protected void clean() { + // individual for each artefact + } + + + protected abstract String getName(); + + protected abstract String getNames(); + + protected abstract void setArtefacts(Artefacts artefact, Set artefacts); +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlReaderFactory.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlReaderFactory.java new file mode 100644 index 0000000..3526d04 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlReaderFactory.java @@ -0,0 +1,311 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactImpl; + +public final class XmlReaderFactory { + + private XmlReaderFactory() { + } + + public static XmlStructureReader newInstance() { + HeaderReader headerReader = new HeaderReader(); + return new XmlStructureReader( + headerReader, + XmlReaderFactory.readers() + ); + } + + private static CodelistReader createCodelistReader() { + return new CodelistReader( + getAnnotableReader(), + getNameableReader(), + getCodelistExtensionReader(), + getCodeImplReader() + ); + } + + private static CodeImplReader getCodeImplReader() { + return new CodeImplReader(); + } + + private static AgencySchemeReader createAgencySchemeReader() { + return new AgencySchemeReader( + getAnnotableReader(), + getNameableReader(), + getOrganisationReader() + ); + } + + private static CategorisationReader createCategorisationReader() { + return new CategorisationReader(getAnnotableReader(), getNameableReader()); + } + + private static CategorySchemeMapReader createCategorySchemeMapReader() { + return new CategorySchemeMapReader(getAnnotableReader(), getNameableReader()); + } + + private static CategorySchemeReader createCategorySchemeReader() { + return new CategorySchemeReader(getAnnotableReader(), getNameableReader()); + } + + private static ConceptSchemeMapReader createConceptSchemeMapReader() { + return new ConceptSchemeMapReader(getAnnotableReader(), getNameableReader()); + } + + private static ConceptSchemeReader createConceptSchemeReader() { + return new ConceptSchemeReader( + getAnnotableReader(), + getNameableReader(), + getRepresentationReader() + ); + } + + private static DataConsumerSchemeReader createDataConsumerSchemeReader() { + return new DataConsumerSchemeReader( + getAnnotableReader(), + getNameableReader(), + getOrganisationReader() + ); + } + + private static DataflowReader createDataFlowReader() { + return new DataflowReader(getAnnotableReader(), getNameableReader()); + } + + private static DataConstraintReader createDataConstraintReader() { + return new DataConstraintReader( + getAnnotableReader(), + getNameableReader(), + getReleaseCalendarReader(), + getMemberSelectionReader() + ); + } + + private static DataProviderSchemeReader createDataProviderSchemeReader() { + return new DataProviderSchemeReader( + getAnnotableReader(), + getNameableReader(), + getOrganisationReader() + ); + } + + private static DataStructureDefinitionReader createDataStructureDefinitionReader() { + + AttributeListReader attributeListReader = new AttributeListReader(getRepresentationReader(), getAnnotableReader()); + DimensionListReader dimensionListReader = new DimensionListReader(getRepresentationReader(), getAnnotableReader()); + MeasureListReader measureListReader = new MeasureListReader(getRepresentationReader(), getAnnotableReader()); + + return new DataStructureDefinitionReader( + getAnnotableReader(), + getNameableReader(), + attributeListReader, + dimensionListReader, + measureListReader + ); + } + + private static MetadataStructureDefinitionReader createMetadataStructureDefinitionReader() { + return new MetadataStructureDefinitionReader( + getAnnotableReader(), + getNameableReader(), + getRepresentationReader() + ); + } + + private static HierarchyAssociationReader createHierarchyAssociationReader() { + return new HierarchyAssociationReader( + getAnnotableReader(), + getNameableReader() + ); + } + + private static HierarchyReader createHierarchyReader() { + return new HierarchyReader(getAnnotableReader(), getNameableReader()); + } + + private static MetadataConstraintReader createMetadataConstraintReader() { + return new MetadataConstraintReader( + getAnnotableReader(), + getNameableReader(), + getMemberSelectionReader(), + getReleaseCalendarReader() + ); + } + + private static MetadataflowReader createMetadataflowReader() { + return new MetadataflowReader(getAnnotableReader(), getNameableReader()); + } + + private static MetadataProviderSchemeReader createMetadataProviderSchemeReader() { + return new MetadataProviderSchemeReader( + getAnnotableReader(), + getNameableReader(), + getOrganisationReader() + ); + } + + private static MetadataProvisionAgreementReader createMetadataProvisionAgreementReader() { + return new MetadataProvisionAgreementReader( + getAnnotableReader(), + getNameableReader() + ); + } + + private static OrganisationSchemeMapReader createOrganisationSchemeMapReader() { + return new OrganisationSchemeMapReader( + getAnnotableReader(), + getNameableReader() + ); + } + + private static OrganisationUnitSchemeReader createOrganisationUnitSchemeReader() { + return new OrganisationUnitSchemeReader( + getAnnotableReader(), + getNameableReader(), + getOrganisationReader() + ); + } + + private static ProcessReader createProcessReader() { + return new ProcessReader( + getAnnotableReader(), + getNameableReader() + ); + } + + private static ProvisionAgreementReader createProvisionAgreementReader() { + return new ProvisionAgreementReader( + getAnnotableReader(), + getNameableReader() + ); + } + + private static ReportingTaxonomyReader createReportingTaxonomyReader() { + return new ReportingTaxonomyReader( + getAnnotableReader(), + getNameableReader() + ); + } + + private static ReportingTaxonomyMapReader createReportingTaxonomyMapReader() { + return new ReportingTaxonomyMapReader( + getAnnotableReader(), + getNameableReader() + ); + } + + private static RepresentationMapReader createRepresentationMapReader() { + return new RepresentationMapReader( + getAnnotableReader(), + getNameableReader() + ); + } + + private static StructureMapReader createStructureMapReader() { + return new StructureMapReader( + getAnnotableReader(), + getNameableReader() + ); + } + + private static ValueListReader createValueListReader() { + return new ValueListReader( + getAnnotableReader(), + getNameableReader() + ); + } + + private static GeographicCodelistReader createGeographicCodelistReader() { + return new GeographicCodelistReader( + getAnnotableReader(), + getNameableReader(), + getGeoFeatureSetCodeReader(), + getCodelistExtensionReader() + ); + } + + private static GeoGridCodelistReader createGeoGridCodelistReader() { + return new GeoGridCodelistReader( + getAnnotableReader(), + getNameableReader(), + getCodelistExtensionReader(), + getGridCodeReader() + ); + } + + private static RepresentationReader getRepresentationReader() { + return new RepresentationReader(getNameableReader()); + } + + private static OrganisationReader getOrganisationReader() { + return new OrganisationReader( + getAnnotableReader(), + getNameableReader() + ); + } + + private static AnnotableReader getAnnotableReader() { + return new AnnotableReader(); + } + + private static NameableReader getNameableReader() { + return new NameableReader(); + } + + private static ReleaseCalendarReader getReleaseCalendarReader() { + return new ReleaseCalendarReader(); + } + + private static MemberSelectionReader getMemberSelectionReader() { + return new MemberSelectionReader(); + } + + private static GeoFeatureSetCodeReader getGeoFeatureSetCodeReader() { + return new GeoFeatureSetCodeReader(); + } + + private static GridCodeReader getGridCodeReader() { + return new GridCodeReader(); + } + + private static CodelistExtensionReader getCodelistExtensionReader() { + return new CodelistExtensionReader(); + } + + private static List> readers() { + return List.of( + createAgencySchemeReader(), + createCategorisationReader(), + createCategorySchemeReader(), + createCategorySchemeMapReader(), + createCodelistReader(), + createConceptSchemeReader(), + createConceptSchemeMapReader(), + createDataConstraintReader(), + createDataConsumerSchemeReader(), + createDataProviderSchemeReader(), + createDataStructureDefinitionReader(), + createDataFlowReader(), + createHierarchyReader(), + createHierarchyAssociationReader(), + createMetadataConstraintReader(), + createMetadataProviderSchemeReader(), + createMetadataProvisionAgreementReader(), + createMetadataStructureDefinitionReader(), + createMetadataflowReader(), + createOrganisationSchemeMapReader(), + createOrganisationUnitSchemeReader(), + createProcessReader(), + createProvisionAgreementReader(), + createReportingTaxonomyReader(), + createReportingTaxonomyMapReader(), + createRepresentationMapReader(), + createStructureMapReader(), + createValueListReader(), + createGeographicCodelistReader(), + createGeoGridCodelistReader() + ); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlReaderUtils.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlReaderUtils.java new file mode 100644 index 0000000..23f6e97 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlReaderUtils.java @@ -0,0 +1,225 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.net.URI; +import java.net.URL; +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.ChronoField; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.ComponentImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactImpl; +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.infomodel.sdmx30.Version; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import lombok.SneakyThrows; +import org.apache.commons.lang3.StringUtils; + +public final class XmlReaderUtils { + + private XmlReaderUtils() { + } + + public static int moveToNextTag(XMLStreamReader streamReader) throws XMLStreamException { + int event = streamReader.next(); + + while (event != XMLStreamConstants.START_ELEMENT && event != XMLStreamConstants.END_ELEMENT) { + event = streamReader.next(); + } + return event; + } + + public static void getPartyNames(XMLStreamReader reader, Party party) throws XMLStreamException { + if (reader.getEventType() == XMLStreamConstants.END_ELEMENT) { + party.setName(new InternationalString(new HashMap<>())); + return; + } + + Map names = new HashMap<>(); + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.SENDER, XmlConstants.RECEIVER)) { + if (!reader.getLocalName().equals(XmlConstants.NAME)) { + return; + } + + String locale = reader.getAttributeValue(XmlConstants.XML_1998_NAMESPACE, XmlConstants.LANG); + String text = reader.getElementText(); + names.put(locale, text); + moveToNextTag(reader); + } + + party.setName(new InternationalString(names)); + } + + public static boolean isEndingTag(XMLStreamReader reader, String... names) { + if (reader.getEventType() != XMLStreamConstants.END_ELEMENT) { + return false; + } + + return names.length == 0 || Arrays.stream(names).anyMatch(name -> name.equals(reader.getLocalName())); + } + + public static boolean isNotEndingTag(XMLStreamReader reader, String... names) { + return !isEndingTag(reader, names); + } + + public static void setCommonAttributes(XMLStreamReader reader, MaintainableArtefactImpl artefact) { + + setUri(reader, artefact); + + setStructureUrl(reader, artefact); + + setServiceUrl(reader, artefact); + + setId(reader, artefact); + + setAgencyId(reader, artefact); + + setVersion(reader, artefact); + + setExternalReference(reader, artefact); + + setValidTo(reader, artefact); + + setValidFrom(reader, artefact); + + } + + public static void setValidFrom(XMLStreamReader reader, MaintainableArtefactImpl artefact) { + String validFrom = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VALID_FROM); + if (validFrom != null) { + artefact.setValidFrom(validFrom); + } + } + + public static void setValidTo(XMLStreamReader reader, MaintainableArtefactImpl artefact) { + String validTo = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VALID_TO); + if (validTo != null) { + artefact.setValidTo(validTo); + } + } + + @SneakyThrows + public static void setStructureUrl(XMLStreamReader reader, MaintainableArtefactImpl artefact) { + String structureUrl = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.STRUCTURE_URL); + if (structureUrl != null) { + artefact.setStructureUrl(new URL(structureUrl)); + } + } + + @SneakyThrows + public static void setUri(XMLStreamReader reader, MaintainableArtefactImpl artefact) { + String uri = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.URI); + if (uri != null) { + artefact.setUri(new URI(uri)); + } + } + + public static void setExternalReference(XMLStreamReader reader, MaintainableArtefactImpl artefact) { + String isExternalReference = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.IS_EXTERNAL_REFERENCE); + if (isExternalReference != null) { + artefact.setExternalReference(Boolean.parseBoolean(isExternalReference)); + } + } + + public static void setVersion(XMLStreamReader reader, MaintainableArtefactImpl artefact) { + String version = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.VERSION); + if (version == null) { + throw new IllegalArgumentException("version of " + artefact + XmlConstants.CANNOT_BE_NULL); + } + artefact.setVersion(Version.createFromString(version)); + } + + public static void setAgencyId(XMLStreamReader reader, MaintainableArtefactImpl artefact) { + String agencyID = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.AGENCY_ID); + if (agencyID == null) { + throw new IllegalArgumentException("agencyID of " + artefact + XmlConstants.CANNOT_BE_NULL); + } + artefact.setOrganizationId(agencyID); + } + + public static void setId(XMLStreamReader reader, MaintainableArtefactImpl artefact) { + String id = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID); + if (id == null) { + throw new IllegalArgumentException("id of " + artefact + XmlConstants.CANNOT_BE_NULL); + } + artefact.setId(id); + } + + @SneakyThrows + public static void setServiceUrl(XMLStreamReader reader, MaintainableArtefactImpl artefact) { + String serviceUrl = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.SERVICE_URL); + if (serviceUrl != null) { + artefact.setServiceUrl(new URL(serviceUrl)); + } + } + + public static void readConceptIdentity(XMLStreamReader reader, ComponentImpl attribute) throws XMLStreamException { + Optional.ofNullable(reader.getElementText()) + .map(String::trim) + .map(IdentifiableArtefactReferenceImpl::new) + .ifPresent(attribute::setConceptIdentity); + } + + public static void readConceptRole(XMLStreamReader reader, List conceptRoles) throws XMLStreamException { + Optional.ofNullable(reader.getElementText()) + .map(IdentifiableArtefactReferenceImpl::new) + .ifPresent(conceptRoles::add); + } + + public static Instant getDate(XMLStreamReader reader, String attributeName) { + return Optional.ofNullable(reader.getAttributeValue(StringUtils.EMPTY, attributeName)) + .map(LocalDate::parse) + .map(XmlReaderUtils::convertToInstant) + .orElse(null); + } + + public static Instant convertToInstant(LocalDate date) { + return date == null ? null : date.atStartOfDay().toInstant(ZoneOffset.UTC); + } + + public static boolean isNotEmptyOrNullElementText(String text) { + return StringUtils.isNotBlank(text); + } + + public static Instant getInstantFromYearString(String yearString) { + return Instant.from((new DateTimeFormatterBuilder().appendPattern(XmlConstants.YEAR_PATTERN) + .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1) + .parseDefaulting(ChronoField.DAY_OF_MONTH, 1) + .parseDefaulting(ChronoField.HOUR_OF_DAY, 0) + .parseDefaulting(ChronoField.MINUTE_OF_DAY, 0) + .parseDefaulting(ChronoField.SECOND_OF_DAY, 0) + .parseDefaulting(ChronoField.NANO_OF_SECOND, 0) + .toFormatter() + .withZone(ZoneId.of("UTC"))).parse(yearString)); + } + + public static Boolean getIncluded(XMLStreamReader reader) { + String included = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.INCLUDE); + return Boolean.parseBoolean(included); + } + + public static Boolean getRemovePrefix(XMLStreamReader reader) { + String removePrefix = reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.REMOVE_PREFIX); + return Boolean.parseBoolean(removePrefix); + } + + public static String getId(XMLStreamReader reader) { + return reader.getAttributeValue(StringUtils.EMPTY, XmlConstants.ID); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlStructureReader.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlStructureReader.java new file mode 100644 index 0000000..cfb3949 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/reader/XmlStructureReader.java @@ -0,0 +1,147 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.isNotEndingTag; +import static com.epam.jsdmx.xml30.structure.reader.XmlReaderUtils.moveToNextTag; + +import java.io.InputStream; +import java.net.URISyntaxException; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactImpl; +import com.epam.jsdmx.serializer.sdmx30.common.DataLocation; +import com.epam.jsdmx.serializer.sdmx30.common.Header; +import com.epam.jsdmx.serializer.sdmx30.structure.StructureReader; +import com.epam.jsdmx.xml30.structure.writer.XmlConstants; + +import lombok.SneakyThrows; + +/** + * Streaming deserialization for xml (3.0) + */ +public class XmlStructureReader implements StructureReader { + + private static final Set SUPPORTED_STRUCTURES = Set.of( + XmlConstants.CODELISTS, + XmlConstants.HIERARCHIES, + XmlConstants.CONCEPT_SCHEMES, + XmlConstants.DATA_STRUCTURES, + XmlConstants.DATAFLOWS, + XmlConstants.METADATA_STRUCTURES, + XmlConstants.METADATA_FLOWS, + XmlConstants.REPRESENTATION_MAPS, + XmlConstants.STRUCTURE_MAPS, + XmlConstants.CATEGORISATIONS, + XmlConstants.CATEGORY_SCHEMES, + XmlConstants.AGENCY_SCHEMES, + XmlConstants.CATEGORY_SCHEME_MAPS, + XmlConstants.CONCEPT_SCHEME_MAPS, + XmlConstants.DATA_CONSUMER_SCHEMES, + XmlConstants.DATA_PROVIDER_SCHEMES, + XmlConstants.DATA_CONSTRAINTS, + XmlConstants.METADATA_PROVIDER_SCHEMES, + XmlConstants.HIERARCHY_ASSOCIATIONS, + XmlConstants.METADATA_CONSTRAINTS, + XmlConstants.METADATA_PROVISION_AGREEMENTS, + XmlConstants.ORGANISATION_SCHEME_MAPS, + XmlConstants.ORGANISATION_UNIT_SCHEMES, + XmlConstants.PROCESSES, + XmlConstants.PROVISION_AGREEMENTS, + XmlConstants.REPORTING_TAXONOMIES, + XmlConstants.REPORTING_TAXONOMY_MAPS, + XmlConstants.VALUE_LISTS, + XmlConstants.GEO_CODELISTS, + XmlConstants.GEOGRID_CODELISTS + ); + + private final HeaderReader headerReader; + + private final List> readers; + + public XmlStructureReader(HeaderReader headerReader, List> readers) { + this.headerReader = headerReader; + this.readers = List.copyOf(readers); + } + + public Artefacts read(XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + try { + moveToNextTag(reader); + Artefacts artefacts = new ArtefactsImpl(); + while (isNotEndingTag(reader, XmlConstants.MES_STRUCTURE)) { + moveToNextTag(reader); + String localName = reader.getLocalName(); + switch (localName) { + case XmlConstants.HEADER: + getHeader(reader); + break; + case XmlConstants.MES_STRUCTURES: + readStructures(artefacts, reader); + moveToNextTag(reader); + break; + default: + throw new IllegalArgumentException("Structure does not support element: " + localName); + } + } + return artefacts; + } finally { + reader.close(); + } + } + + @Override + @SneakyThrows + public Artefacts read(DataLocation location) { + final InputStream inputStream = location.inputStream(); + XMLInputFactory xmlInFact = XMLInputFactory.newInstance(); + xmlInFact.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE); + XMLStreamReader reader = xmlInFact.createXMLStreamReader(inputStream); + return read(reader); + } + + private Header getHeader(XMLStreamReader reader) throws XMLStreamException { + return headerReader.read(reader); + } + + private void readStructures(Artefacts artefacts, XMLStreamReader reader) throws XMLStreamException, URISyntaxException { + moveToNextTag(reader); + while (isNotEndingTag(reader, XmlConstants.MES_STRUCTURES)) { + String localName = reader.getLocalName(); + + if (!SUPPORTED_STRUCTURES.contains(localName)) { + throw new IllegalStateException("Unknown structure type: " + localName); + } + + Optional> xmlReader = readers.stream() + .filter(read -> localName.equals(read.getNames())) + .findAny(); + + if (xmlReader.isPresent()) { + readStructures(reader, artefacts, xmlReader.get()); + moveToNextTag(reader); + } + } + } + + private void readStructures(XMLStreamReader reader, + Artefacts artefacts, + XmlReader xmlReader) throws XMLStreamException, URISyntaxException { + Set maintainableArtefacts = new HashSet<>(); + while (isNotEndingTag(reader, xmlReader.getNames())) { + moveToNextTag(reader); + if (reader.getLocalName().equals(xmlReader.getName())) { + maintainableArtefacts.add(xmlReader.read(reader)); + xmlReader.clean(); + } + } + xmlReader.setArtefacts(artefacts, maintainableArtefacts); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/AgencySchemeWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/AgencySchemeWriter.java new file mode 100644 index 0000000..d2aa351 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/AgencySchemeWriter.java @@ -0,0 +1,68 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Agency; +import com.epam.jsdmx.infomodel.sdmx30.AgencyScheme; +import com.epam.jsdmx.infomodel.sdmx30.AgencySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Version; + +public class AgencySchemeWriter extends XmlWriter { + + private final OrganisationWriter organisationWriter; + + public AgencySchemeWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + OrganisationWriter organisationWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.organisationWriter = organisationWriter; + } + + @Override + protected void writeAttributes(AgencyScheme agencyScheme, XMLStreamWriter writer) throws XMLStreamException { + AgencySchemeImpl agencySchemeImpl = (AgencySchemeImpl) agencyScheme; + agencySchemeImpl.setVersion(Version.createFromString(XmlConstants.DEFAULT_VERSION)); + commonAttributesWriter.writeAttributes( + "AGENCIES", + "SDMX", + agencyScheme.getUri(), + agencySchemeImpl.getUrn(), + null, + agencyScheme.isExternalReference(), + agencyScheme.getServiceUrl(), + agencyScheme.getStructureUrl(), + agencyScheme.getValidToString(), + agencyScheme.getValidFromString(), + writer + ); + } + + @Override + protected void writeCustomAttributeElements(AgencyScheme agencyScheme, XMLStreamWriter writer) throws XMLStreamException { + List agencies = (List) agencyScheme.getItems(); + organisationWriter.writeOrganisation(agencies, writer, XmlConstants.AGENCY); + } + + @Override + protected String getName() { + return XmlConstants.AGENCY_SCHEME; + } + + @Override + protected String getNamePlural() { + return XmlConstants.AGENCY_SCHEMES; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getAgencySchemes(); + } + +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/AnnotableWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/AnnotableWriter.java new file mode 100644 index 0000000..5cbd635 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/AnnotableWriter.java @@ -0,0 +1,63 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.AnnotableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.Annotation; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.InternationalUri; + +import org.apache.commons.collections4.CollectionUtils; + +public class AnnotableWriter { + + protected void write(List annotations, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isEmpty(annotations)) { + return; + } + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.COM_ANNOTATIONS); + for (Annotation annotation : annotations) { + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.COM_ANNOTATION); + String id = annotation.getId(); + if (id != null) { + writer.writeAttribute(XmlConstants.ID, id); + } + + String title = annotation.getTitle(); + if (title != null) { + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.COM_ANNOTATION_TITLE); + writer.writeCharacters(title); + writer.writeEndElement(); + } + + String type = annotation.getType(); + if (type != null) { + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.COM_ANNOTATION_TYPE); + writer.writeCharacters(type); + writer.writeEndElement(); + } + + InternationalUri url = annotation.getUrl(); + XmlWriterUtils.writeInternationalUri(url, writer, XmlConstants.COMMON + XmlConstants.COM_ANNOTATION_URL); + + InternationalString text = annotation.getText(); + XmlWriterUtils.writeInternationalString(text, writer, XmlConstants.COMMON + XmlConstants.COM_ANNOTATION_TEXT); + + String value = annotation.getValue(); + if (value != null) { + writer.writeStartElement(XmlConstants.COMMON + XmlConstants.COM_ANNOTATION_VALUE); + writer.writeCharacters(value); + writer.writeEndElement(); + } + writer.writeEndElement(); + } + writer.writeEndElement(); + } + + public void write(AnnotableArtefact artefact, XMLStreamWriter writer) throws XMLStreamException { + write(artefact.getAnnotations(), writer); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/AttributeListWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/AttributeListWriter.java new file mode 100644 index 0000000..be86d83 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/AttributeListWriter.java @@ -0,0 +1,169 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.net.URI; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.AttributeRelationship; +import com.epam.jsdmx.infomodel.sdmx30.DataAttribute; +import com.epam.jsdmx.infomodel.sdmx30.DimensionRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.GroupRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureRelationship; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeRef; +import com.epam.jsdmx.infomodel.sdmx30.ObservationRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.Representation; + +import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; + +@AllArgsConstructor +public class AttributeListWriter { + + private final AnnotableWriter annotableWriter; + private final RepresentationWriter representationWriter; + + private static void writeMetaAttributeReference(XMLStreamWriter writer, MetadataAttributeRef metadataAttributeRef) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.METADATA_ATTRIBUTE_REFERENCE); + XmlWriterUtils.writeCharacters(metadataAttributeRef.getId(), writer); + writer.writeEndElement(); + } + + public void writeAttributeList(AttributeDescriptor attributeDescriptor, XMLStreamWriter writer) throws XMLStreamException { + if (attributeDescriptor != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.ATTRIBUTE_LIST); + + XmlWriterUtils.writeIdUriAttributes(writer, XmlConstants.ATTRIBUTE_DESCRIPTOR_ID, attributeDescriptor.getUri()); + if (attributeDescriptor.getContainer() != null) { + XmlWriterUtils.writeUrn(attributeDescriptor.getUrn(), writer); + } + + annotableWriter.write(attributeDescriptor, writer); + List components = attributeDescriptor.getComponents(); + List metadataAttributes = attributeDescriptor.getMetadataAttributes(); + writeMetadataAttributeUsage(metadataAttributes, writer); + writeAttribute(components, writer); + writer.writeEndElement(); + } + + } + + private void writeMetadataAttributeUsage(List metadataAttributes, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(metadataAttributes)) { + for (MetadataAttributeRef metadataAttributeRef : metadataAttributes) { + writeMetaAttribute(writer, metadataAttributeRef); + } + } + } + + private void writeMetaAttribute(XMLStreamWriter writer, MetadataAttributeRef metadataAttributeRef) throws XMLStreamException { + if (metadataAttributeRef != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.METADATA_ATTRIBUTE_USAGE); + URI uri = metadataAttributeRef.getUri(); + if (uri != null) { + writer.writeAttribute(XmlConstants.URI, uri.toString()); + } + if (metadataAttributeRef.getContainer() != null) { + String urn = metadataAttributeRef.getUrn(); + if (urn != null) { + writer.writeAttribute(XmlConstants.URN, urn); + } + } + annotableWriter.write(metadataAttributeRef, writer); + writeMetaAttributeReference(writer, metadataAttributeRef); + writeAttributeRelationship(writer, metadataAttributeRef.getMetadataRelationship()); + writer.writeEndElement(); + } + } + + private void writeAttribute(List components, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(components)) { + for (DataAttribute attribute : components) { + writeAttribute(writer, attribute); + } + } + } + + private void writeAttribute(XMLStreamWriter writer, DataAttribute attribute) throws XMLStreamException { + if (attribute != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.ATTRIBUTE); + XmlWriterUtils.writeIdUriAttributes(writer, attribute.getId(), attribute.getUri()); + if (attribute.getContainer() != null) { + XmlWriterUtils.writeUrn(attribute.getUrn(), writer); + } + boolean mandatory = attribute.isMandatory(); + writer.writeAttribute(XmlConstants.USAGE, mandatory ? XmlConstants.MANDATORY : XmlConstants.OPTIONAL); + this.annotableWriter.write(attribute, writer); + XmlWriterUtils.writeConceptIdentity(writer, attribute); + Representation localRepresentation = attribute.getLocalRepresentation(); + if (localRepresentation != null) { + representationWriter.writeRepresentation(writer, localRepresentation, XmlConstants.LOCAL_REPRESENTATION); + } + XmlWriterUtils.writeConceptRoles(writer, attribute.getConceptRoles()); + writeAttributeRelationship(writer, attribute.getAttributeRelationship()); + writeMeasureRelationship(writer, attribute.getMeasureRelationship()); + writer.writeEndElement(); + } + } + + private void writeMeasureRelationship(XMLStreamWriter writer, MeasureRelationship measureRelationship) throws XMLStreamException { + if (measureRelationship != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.MEASURE_RELATIONSHIP); + List measures = measureRelationship.getMeasures(); + if (CollectionUtils.isNotEmpty(measures)) { + for (String measure : measures) { + if (measure != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.MEASURE); + writer.writeCharacters(measure); + writer.writeEndElement(); + } + } + } + writer.writeEndElement(); + } + } + + private void writeAttributeRelationship(XMLStreamWriter writer, AttributeRelationship attributeRelationship) throws XMLStreamException { + if (attributeRelationship != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.ATTRIBUTE_RELATIONSHIP); + if (attributeRelationship instanceof DimensionRelationshipImpl) { + DimensionRelationshipImpl dimensionRelationship = (DimensionRelationshipImpl) attributeRelationship; + writeDimensions(writer, dimensionRelationship); + } + + if (attributeRelationship instanceof ObservationRelationshipImpl) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.OBSERVATION); + writer.writeEndElement(); + } + + if (attributeRelationship instanceof GroupRelationshipImpl) { + GroupRelationshipImpl groupRelationship = (GroupRelationshipImpl) attributeRelationship; + writeGroup(writer, groupRelationship); + } + writer.writeEndElement(); + } + } + + private void writeGroup(XMLStreamWriter writer, GroupRelationshipImpl groupRelationship) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.GROUP); + if (groupRelationship.getGroupKey() != null) { + writer.writeCharacters(groupRelationship.getGroupKey()); + } + writer.writeEndElement(); + } + + private void writeDimensions(XMLStreamWriter writer, DimensionRelationshipImpl dimensionRelationship) throws XMLStreamException { + List dimensions = dimensionRelationship.getDimensions(); + if (CollectionUtils.isNotEmpty(dimensions)) { + for (String dimension : dimensions) { + if (dimension != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.DIMENSION); + writer.writeCharacters(dimension); + writer.writeEndElement(); + } + } + } + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CategorisationWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CategorisationWriter.java new file mode 100644 index 0000000..286bb77 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CategorisationWriter.java @@ -0,0 +1,62 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Categorisation; + +public class CategorisationWriter extends XmlWriter { + + private final UrnWriter urnWriter; + + public CategorisationWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + UrnWriter urnWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.urnWriter = urnWriter; + } + + @Override + protected void writeAttributes(Categorisation categorisation, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(categorisation, writer); + } + + @Override + protected void writeCustomAttributeElements(Categorisation categorisation, XMLStreamWriter writer) throws XMLStreamException { + + ArtefactReference categorizedArtefact = categorisation.getCategorizedArtefact(); + ArtefactReference categorizedBy = categorisation.getCategorizedBy(); + if (categorizedArtefact != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.SOURCE); + urnWriter.writeUrnCharacters(categorizedArtefact, writer); + writer.writeEndElement(); + } + + if (categorizedBy != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.TARGET); + urnWriter.writeUrnCharacters(categorizedBy, writer); + writer.writeEndElement(); + } + } + + @Override + protected String getName() { + return XmlConstants.CATEGORISATION; + } + + @Override + protected String getNamePlural() { + return XmlConstants.CATEGORISATIONS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getCategorisations(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeMapWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeMapWriter.java new file mode 100644 index 0000000..95bc336 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeMapWriter.java @@ -0,0 +1,50 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeMap; + +public class CategorySchemeMapWriter extends XmlWriter { + + private final ItemSchemeMapWriter itemSchemeMapWriter; + + public CategorySchemeMapWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + ItemSchemeMapWriter itemSchemeMapWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.itemSchemeMapWriter = itemSchemeMapWriter; + } + + @Override + protected void writeAttributes(CategorySchemeMap categorySchemeMap, XMLStreamWriter writer) throws XMLStreamException { + commonAttributesWriter.writeAttributes(categorySchemeMap, writer); + } + + @Override + protected void writeCustomAttributeElements(CategorySchemeMap categorySchemeMap, XMLStreamWriter writer) throws XMLStreamException { + itemSchemeMapWriter.writeSource(writer, categorySchemeMap.getSource(), XmlConstants.STRUCTURE + XmlConstants.SOURCE); + itemSchemeMapWriter.writeTarget(writer, categorySchemeMap.getTarget(), XmlConstants.STRUCTURE + XmlConstants.TARGET); + itemSchemeMapWriter.writeItems(writer, categorySchemeMap.getItemMaps(), annotableWriter); + } + + @Override + protected String getName() { + return XmlConstants.CATEGORY_SCHEME_MAP; + } + + @Override + protected String getNamePlural() { + return XmlConstants.CATEGORY_SCHEME_MAPS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getCategorySchemeMaps(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeWriter.java new file mode 100644 index 0000000..be9ce47 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeWriter.java @@ -0,0 +1,65 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Category; +import com.epam.jsdmx.infomodel.sdmx30.CategoryScheme; + +import org.apache.commons.collections.CollectionUtils; + +public class CategorySchemeWriter extends XmlWriter { + + public CategorySchemeWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + } + + @Override + protected void writeAttributes(CategoryScheme categoryScheme, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(categoryScheme, writer); + writer.writeAttribute(XmlConstants.IS_PARTIAL, String.valueOf(categoryScheme.isPartial())); + } + + @Override + protected void writeCustomAttributeElements(CategoryScheme categoryScheme, XMLStreamWriter writer) throws XMLStreamException { + writeCategory(categoryScheme.getItems(), writer); + } + + @Override + protected String getName() { + return XmlConstants.CATEGORY_SCHEME; + } + + @Override + protected String getNamePlural() { + return XmlConstants.CATEGORY_SCHEMES; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getCategorySchemes(); + } + + private void writeCategory(List items, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(items)) { + for (Category category : items) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CATEGORY); + XmlWriterUtils.writeIdUriAttributes(writer, category.getId(), category.getUri()); + if (category.getContainer() != null) { + writer.writeAttribute(XmlConstants.URN, category.getUrn()); + } + this.annotableWriter.write(category, writer); + this.nameableWriter.write(category, writer); + writeCategory(category.getHierarchy(), writer); + writer.writeEndElement(); + } + } + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodeListExtensionWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodeListExtensionWriter.java new file mode 100644 index 0000000..95ad173 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodeListExtensionWriter.java @@ -0,0 +1,80 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.CodeSelection; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.ExclusiveCodeSelection; +import com.epam.jsdmx.infomodel.sdmx30.InclusiveCodeSelection; +import com.epam.jsdmx.infomodel.sdmx30.MemberValue; +import com.epam.jsdmx.infomodel.sdmx30.StreamUtils; + +import org.apache.commons.collections.CollectionUtils; + +public class CodeListExtensionWriter { + + private final UrnWriter urnWriter; + + public CodeListExtensionWriter(UrnWriter urnWriter) { + this.urnWriter = urnWriter; + } + + public void writeCodeListExtensions(XMLStreamWriter writer, List codelistExtensions) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(codelistExtensions)) { + for (CodelistExtension extension : codelistExtensions) { + writeExtension(extension, writer); + } + } + } + + public void writeExtension(CodelistExtension extension, XMLStreamWriter writer) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CODELIST_EXTENSION); + + String prefix = extension.getPrefix(); + if (prefix != null) { + writer.writeAttribute(XmlConstants.PREFIX, prefix); + } + + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CODELIST); + urnWriter.writeUrnCharacters(extension.getCodelist(), writer); + writer.writeEndElement(); + + writeCodeSelection(writer, extension.getCodeSelection()); + + writer.writeEndElement(); + } + + private void writeCodeSelection(XMLStreamWriter writer, CodeSelection codeSelection) throws XMLStreamException { + if (codeSelection instanceof ExclusiveCodeSelection || codeSelection instanceof InclusiveCodeSelection) { + List members = codeSelection.getMembers(); + String localNamePart = codeSelection instanceof ExclusiveCodeSelection + ? XmlConstants.EXCLUSIVE_CODE_SELECTION + : XmlConstants.INCLUSIVE_CODE_SELECTION; + + writer.writeStartElement(XmlConstants.STRUCTURE + localNamePart); + writeMemberValues(writer, members); + writer.writeEndElement(); + } + } + + private void writeMemberValues(XMLStreamWriter writer, List members) throws XMLStreamException { + List nonNullMemberValues = StreamUtils.streamOfNullable(members) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + for (MemberValue memberValue : nonNullMemberValues) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.MEMBER_VALUE); + writer.writeAttribute(XmlConstants.CASCADE_VALUES, memberValue.getCascadeValue().name().toLowerCase()); + String value = memberValue.getValue(); + if (value != null) { + writer.writeCharacters(value); + } + writer.writeEndElement(); + } + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodeWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodeWriter.java new file mode 100644 index 0000000..748a475 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodeWriter.java @@ -0,0 +1,62 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.net.URI; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Code; + +public abstract class CodeWriter { + + private final UrnWriter urnWriter; + private final NameableWriter nameableWriter; + private final AnnotableWriter annotableWriter; + + protected CodeWriter(UrnWriter urnWriter, NameableWriter nameableWriter, AnnotableWriter annotableWriter) { + this.urnWriter = urnWriter; + this.nameableWriter = nameableWriter; + this.annotableWriter = annotableWriter; + } + + protected void write(T code, + XMLStreamWriter writer, + String name) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + name); + writeAttributes(code, writer); + writeElements(code, writer); + writer.writeEndElement(); + } + + protected void writeAttributes(T code, XMLStreamWriter writer) throws XMLStreamException { + String id = code.getId(); + if (id != null) { + writer.writeAttribute(XmlConstants.ID, id); + } + + URI uri = code.getUri(); + if (uri != null) { + writer.writeAttribute(XmlConstants.URI, uri.toString()); + } + + if (code.getContainer() != null) { + String urn = code.getUrn(); + if (urn != null) { + urnWriter.writeUrn(urn, writer); + } + } + } + + protected void writeElements(T code, + XMLStreamWriter writer) throws XMLStreamException { + String parentId = code.getParentId(); + annotableWriter.write(code, writer); + nameableWriter.write(code, writer); + + if (parentId != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.STRUCTURE_PARENT); + writer.writeCharacters(parentId); + writer.writeEndElement(); + } + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodeWriterImpl.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodeWriterImpl.java new file mode 100644 index 0000000..afa368f --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodeWriterImpl.java @@ -0,0 +1,9 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import com.epam.jsdmx.infomodel.sdmx30.Code; + +public class CodeWriterImpl extends CodeWriter { + public CodeWriterImpl(UrnWriter urnWriter, NameableWriter nameableWriter, AnnotableWriter annotableWriter) { + super(urnWriter, nameableWriter, annotableWriter); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodelistWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodelistWriter.java new file mode 100644 index 0000000..64b8700 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CodelistWriter.java @@ -0,0 +1,69 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Code; +import com.epam.jsdmx.infomodel.sdmx30.Codelist; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; + +public class CodelistWriter extends XmlWriter { + + private final CodeWriterImpl codeWriterImpl; + private final CodeListExtensionWriter codeListExtensionWriter; + + public CodelistWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + CodeWriterImpl codeWriterImpl, CodeListExtensionWriter codeListExtensionWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.codeWriterImpl = codeWriterImpl; + this.codeListExtensionWriter = codeListExtensionWriter; + } + + @Override + protected void writeAttributes(Codelist codelist, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(codelist, writer); + writer.writeAttribute(XmlConstants.IS_PARTIAL, String.valueOf(codelist.isPartial())); + } + + public Set extractArtefacts(Artefacts artefacts) { + return artefacts.getCodelists(); + } + + @Override + protected String getName() { + return XmlConstants.CODELIST; + } + + @Override + protected String getNamePlural() { + return XmlConstants.CODELISTS; + } + + @Override + public Optional getWritableArtefactStructureClass() { + return Optional.of(StructureClassImpl.CODELIST); + } + + @Override + protected void writeCustomAttributeElements(Codelist codelist, XMLStreamWriter writer) throws XMLStreamException { + List codes = codelist.getItems(); + for (Code code : codes) { + if (code != null) { + codeWriterImpl.write(code, writer, XmlConstants.STR_CODE); + } + } + + List codelistExtensions = codelist.getExtensions(); + codeListExtensionWriter.writeCodeListExtensions(writer, codelistExtensions); + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CommonAttributesWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CommonAttributesWriter.java new file mode 100644 index 0000000..bb1dbe2 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/CommonAttributesWriter.java @@ -0,0 +1,68 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.net.URI; +import java.net.URL; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.Version; + + +public class CommonAttributesWriter { + + private final UrnWriter urnWriter; + + public CommonAttributesWriter(UrnWriter urnWriter) { + this.urnWriter = urnWriter; + } + + public void writeAttributes(MaintainableArtefact artefact, + XMLStreamWriter writer) throws XMLStreamException { + + writeAttributes( + artefact.getId(), + artefact.getOrganizationId(), + artefact.getUri(), + artefact.getUrn(), + artefact.getVersion(), + artefact.isExternalReference(), + artefact.getServiceUrl(), + artefact.getStructureUrl(), + artefact.getValidToString(), + artefact.getValidFromString(), + writer + ); + } + + public void writeAttributes(String id, + String agencyId, + URI uri, + String urn, + Version version, + boolean isExternalReference, + URL serviceUrl, + URL structureUrl, + String validTo, + String validFrom, + XMLStreamWriter writer) throws XMLStreamException { + + XmlWriterUtils.writeUri(uri, writer); + + urnWriter.writeUrn(urn, writer); + + XmlWriterUtils.writeMandatoryAttribute(agencyId, writer, XmlConstants.AGENCY_ID); + XmlWriterUtils.writeMandatoryAttribute(id, writer, XmlConstants.ID); + + XmlWriterUtils.writeVersion(version, writer); + + writer.writeAttribute(XmlConstants.IS_EXTERNAL_REFERENCE, String.valueOf(isExternalReference)); + + XmlWriterUtils.writeUrl(serviceUrl, writer, XmlConstants.SERVICE_URL); + XmlWriterUtils.writeUrl(structureUrl, writer, XmlConstants.STRUCTURE_URL); + + XmlWriterUtils.writeAttributeIfNotNull(validTo, writer, XmlConstants.VALID_TO); + XmlWriterUtils.writeAttributeIfNotNull(validFrom, writer, XmlConstants.VALID_FROM); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeMapWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeMapWriter.java new file mode 100644 index 0000000..3a5a92e --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeMapWriter.java @@ -0,0 +1,50 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeMap; + +public class ConceptSchemeMapWriter extends XmlWriter { + + private final ItemSchemeMapWriter itemSchemeMapWriter; + + public ConceptSchemeMapWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + ItemSchemeMapWriter itemSchemeMapWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.itemSchemeMapWriter = itemSchemeMapWriter; + } + + @Override + protected void writeAttributes(ConceptSchemeMap conceptSchemeMap, XMLStreamWriter writer) throws XMLStreamException { + commonAttributesWriter.writeAttributes(conceptSchemeMap, writer); + } + + @Override + protected void writeCustomAttributeElements(ConceptSchemeMap conceptSchemeMapc, XMLStreamWriter writer) throws XMLStreamException { + itemSchemeMapWriter.writeSource(writer, conceptSchemeMapc.getSource().getUrn(), XmlConstants.STRUCTURE + XmlConstants.SOURCE); + itemSchemeMapWriter.writeTarget(writer, conceptSchemeMapc.getTarget().getUrn(), XmlConstants.STRUCTURE + XmlConstants.TARGET); + itemSchemeMapWriter.writeItems(writer, conceptSchemeMapc.getItemMaps(), annotableWriter); + } + + @Override + protected String getName() { + return XmlConstants.CONCEPT_SCHEME_MAP; + } + + @Override + protected String getNamePlural() { + return XmlConstants.CONCEPT_SCHEME_MAPS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getConceptSchemeMaps(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeWriter.java new file mode 100644 index 0000000..b3c662d --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeWriter.java @@ -0,0 +1,105 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Concept; +import com.epam.jsdmx.infomodel.sdmx30.ConceptScheme; +import com.epam.jsdmx.infomodel.sdmx30.IsoConceptReference; + +import org.apache.commons.collections4.CollectionUtils; + +public class ConceptSchemeWriter extends XmlWriter { + + private final RepresentationWriter representationWriter; + + public ConceptSchemeWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + RepresentationWriter representationWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.representationWriter = representationWriter; + } + + @Override + protected void writeAttributes(ConceptScheme conceptScheme, XMLStreamWriter writer) throws XMLStreamException { + commonAttributesWriter.writeAttributes(conceptScheme, writer); + writer.writeAttribute(XmlConstants.IS_PARTIAL, String.valueOf(conceptScheme.isPartial())); + } + + @Override + protected void writeCustomAttributeElements(ConceptScheme conceptScheme, XMLStreamWriter writer) throws XMLStreamException { + writeConcepts(conceptScheme, writer); + } + + @Override + protected String getName() { + return XmlConstants.CONCEPT_SCHEME; + } + + @Override + protected String getNamePlural() { + return XmlConstants.CONCEPT_SCHEMES; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getConceptSchemes(); + } + + private void writeConcepts(ConceptScheme conceptScheme, XMLStreamWriter writer) throws XMLStreamException { + List concepts = conceptScheme.getItems(); + if (CollectionUtils.isNotEmpty(concepts)) { + for (Concept concept : concepts) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CONCEPT); + XmlWriterUtils.writeMandatoryAttribute(concept.getId(), writer, XmlConstants.ID); + if (concept.getContainer() != null) { + XmlWriterUtils.writeUrn(concept.getUrn(), writer); + } + XmlWriterUtils.writeUri(concept.getUri(), writer); + annotableWriter.write(concept, writer); + nameableWriter.write(concept, writer); + representationWriter.writeRepresentation(writer, concept.getCoreRepresentation(), XmlConstants.CORE_REPRESENTATION); + writeIsoConcept(writer, concept); + writer.writeEndElement(); + } + } + } + + + private void writeIsoConcept(XMLStreamWriter writer, Concept concept) throws XMLStreamException { + IsoConceptReference isoConceptReference = concept.getIsoConceptReference(); + if (isoConceptReference != null) { + + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.ISOCONCEPT_REFERENCE); + + String conceptId = isoConceptReference.getConceptId(); + String agency = isoConceptReference.getAgency(); + String schemeId = isoConceptReference.getSchemeId(); + + if (agency != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CONCEPT_AGENCY); + writer.writeCharacters(agency); + writer.writeEndElement(); + } + + if (schemeId != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CONCEPT_SCHEME_ID); + writer.writeCharacters(schemeId); + writer.writeEndElement(); + } + + if (conceptId != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CONCEPT_ID); + writer.writeCharacters(conceptId); + writer.writeEndElement(); + } + writer.writeEndElement(); + } + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ContactWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ContactWriter.java new file mode 100644 index 0000000..751005d --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ContactWriter.java @@ -0,0 +1,59 @@ +package com.epam.jsdmx.xml30.structure.writer; + + +import static com.epam.jsdmx.xml30.structure.writer.XmlWriterUtils.writeCharacters; + +import java.net.URI; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Contact; + +import org.apache.commons.collections.CollectionUtils; + +public class ContactWriter { + + public void writeContacts(List contacts, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(contacts)) { + for (Contact contact : contacts) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CONTACT); + + writeElement(writer, contact.getName(), XmlConstants.COMMON + XmlConstants.NAME); + writeElement(writer, contact.getOrganizationUnit(), XmlConstants.STRUCTURE + XmlConstants.DEPARTMENT); + XmlWriterUtils.writeInternationalString(contact.getResponsibility(), writer, XmlConstants.STRUCTURE + XmlConstants.ROLE); + + writeContactData(writer, contact.getTelephone(), XmlConstants.TELEPHONE); + writeContactData(writer, contact.getFax(), XmlConstants.FAX); + writeContactData(writer, contact.getX400(), XmlConstants.X_400); + URI uri = contact.getUri(); + if (uri != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.URI); + writeCharacters(uri.toString(), writer); + writer.writeEndElement(); + } + writeContactData(writer, contact.getEmail(), XmlConstants.EMAIL); + + writer.writeEndElement(); + } + } + } + + private void writeContactData(XMLStreamWriter writer, String data, String name) throws XMLStreamException { + if (data != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + name); + writer.writeCharacters(data); + writer.writeEndElement(); + } + } + + private void writeElement(XMLStreamWriter writer, String contactElement, String nameElement) throws XMLStreamException { + if (contactElement != null) { + writer.writeStartElement(nameElement); + writer.writeAttribute(XmlConstants.XML_LANG, "en"); + writer.writeCharacters(contactElement); + writer.writeEndElement(); + } + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataConstraintWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataConstraintWriter.java new file mode 100644 index 0000000..6cb3442 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataConstraintWriter.java @@ -0,0 +1,198 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ComponentValue; +import com.epam.jsdmx.infomodel.sdmx30.ConstraintRoleType; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegion; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionKey; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.DataKey; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySet; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendar; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; + +import org.apache.commons.collections.CollectionUtils; + +public class DataConstraintWriter extends XmlWriter { + + private final ReleaseCalenderWriter releaseCalenderWriter; + private final MemberSelectionWriter memberSelectionWriter; + + public DataConstraintWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + ReleaseCalenderWriter releaseCalenderWriter, + MemberSelectionWriter memberSelectionWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.releaseCalenderWriter = releaseCalenderWriter; + this.memberSelectionWriter = memberSelectionWriter; + } + + @Override + protected void writeAttributes(DataConstraint artefact, XMLStreamWriter writer) throws XMLStreamException { + commonAttributesWriter.writeAttributes(artefact, writer); + ConstraintRoleType constraintRoleType = artefact.getConstraintRoleType(); + if (constraintRoleType != null) { + writer.writeAttribute(XmlConstants.ROLE_ATTR, XmlConstants.CONSTRAINT_ROLE_STRING.get(constraintRoleType)); + } + } + + private void writeDataConstraints(XMLStreamWriter writer, DataConstraint artefact) throws XMLStreamException { + + List constrainedArtefacts = artefact.getConstrainedArtefacts(); + writeConstrainedArtefacts(writer, constrainedArtefacts); + + ReleaseCalendar releaseCalendar = artefact.getReleaseCalendar(); + releaseCalenderWriter.writeReleaseCalendar(writer, releaseCalendar); + + List dataKeySets = artefact.getDataContentKeys(); + writeDataKeySets(dataKeySets, writer); + + List cubeRegions = artefact.getCubeRegions(); + if (CollectionUtils.isNotEmpty(cubeRegions)) { + for (CubeRegion cubeRegion : cubeRegions) { + if (cubeRegion != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CUBE_REGION); + writer.writeAttribute(XmlConstants.INCLUDE, String.valueOf(cubeRegion.isIncluded())); + annotableWriter.write(cubeRegion, writer); + List memberSelections = cubeRegion.getMemberSelections(); + List cubeRegionKeys = cubeRegion.getCubeRegionKeys(); + writeCubeRegionKeys(cubeRegionKeys, writer); + memberSelectionWriter.writeMemberSelections(writer, memberSelections); + writer.writeEndElement(); + } + } + } + } + + private void writeCubeRegionKeys(List cubeRegionKeys, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(cubeRegionKeys)) { + for (CubeRegionKey cubeRegionKey : cubeRegionKeys) { + if (cubeRegionKey != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.KEY_VALUE); + writer.writeAttribute(XmlConstants.ID, cubeRegionKey.getComponentId()); + XmlWriterUtils.writeInstant(cubeRegionKey.getValidTo(), writer, XmlConstants.VALID_TO); + XmlWriterUtils.writeInstant(cubeRegionKey.getValidFrom(), writer, XmlConstants.VALID_FROM); + writer.writeAttribute(XmlConstants.INCLUDE, String.valueOf(cubeRegionKey.isIncluded())); + writer.writeAttribute(XmlConstants.REMOVE_PREFIX, String.valueOf(cubeRegionKey.isRemovePrefix())); + + memberSelectionWriter.writeSelectionValues(writer, cubeRegionKey.getSelectionValues()); + writer.writeEndElement(); + } + } + } + } + + private void writeConstrainedArtefacts(XMLStreamWriter writer, List constrainedArtefacts) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(constrainedArtefacts)) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CONSTRAINT_ATTACHMENT); + for (ArtefactReference constrained : constrainedArtefacts) { + writeArtefactReference(writer, constrained); + } + writer.writeEndElement(); + } + } + + private void writeArtefactReference(XMLStreamWriter writer, ArtefactReference constrained) throws XMLStreamException { + if (constrained != null) { + StructureClass maintainableStructureClass = constrained.getMaintainableStructureClass(); + String simpleName = maintainableStructureClass.getSimpleName(); + if (simpleName.equals(StructureClassImpl.DATA_PROVIDER.getSimpleName())) { + XmlWriterUtils.writeArtefactReference(writer, XmlConstants.DATA_PROVIDER, constrained.getUrn()); + } + if (simpleName.equals(StructureClassImpl.DATA_STRUCTURE.getSimpleName())) { + XmlWriterUtils.writeArtefactReference(writer, XmlConstants.DATA_STRUCTURE, constrained.getUrn()); + } + if (simpleName.equals(StructureClassImpl.DATAFLOW.getSimpleName())) { + XmlWriterUtils.writeArtefactReference(writer, XmlConstants.DATAFLOW, constrained.getUrn()); + } + if (simpleName.equals(StructureClassImpl.PROVISION_AGREEMENT.getSimpleName())) { + XmlWriterUtils.writeArtefactReference(writer, XmlConstants.PROVISION_AGREEMENT, constrained.getUrn()); + } + } + } + + private void writeDataKeySets(List dataKeySets, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(dataKeySets)) { + for (DataKeySet dataKeySet : dataKeySets) { + if (dataKeySet != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.DATA_KEY_SET); + writer.writeAttribute(XmlConstants.IS_INCLUDED, String.valueOf(dataKeySet.isIncluded())); + List keys = dataKeySet.getKeys(); + writeDataKeys(keys, writer); + writer.writeEndElement(); + } + } + } + } + + private void writeDataKeys(List keys, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(keys)) { + for (DataKey dataKey : keys) { + if (dataKey != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.KEY); + writer.writeAttribute(XmlConstants.INCLUDE, String.valueOf(dataKey.isIncluded())); + XmlWriterUtils.writeInstant(dataKey.getValidTo(), writer, XmlConstants.VALID_TO); + XmlWriterUtils.writeInstant(dataKey.getValidFrom(), writer, XmlConstants.VALID_FROM); + + annotableWriter.write(dataKey, writer); + List keyValues = dataKey.getKeyValues(); + writeKeyValues(keyValues, writer); + List memberSelections = dataKey.getMemberSelections(); + memberSelectionWriter.writeMemberSelections(writer, memberSelections); + writer.writeEndElement(); + } + } + } + } + + private void writeKeyValues(List keyValues, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(keyValues)) { + for (ComponentValue componentValue : keyValues) { + if (componentValue != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.KEY_VALUE); + + writer.writeAttribute(XmlConstants.ID, componentValue.getComponentId()); + writer.writeAttribute(XmlConstants.INCLUDE, String.valueOf(componentValue.isIncluded())); + writer.writeAttribute(XmlConstants.REMOVE_PREFIX, String.valueOf(componentValue.isRemovePrefix())); + + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.VALUE); + XmlWriterUtils.writeCharacters(componentValue.getValue(), writer); + writer.writeEndElement(); + + writer.writeEndElement(); + } + } + } + } + + @Override + protected void writeCustomAttributeElements(DataConstraint artefact, XMLStreamWriter writer) throws XMLStreamException { + writeDataConstraints(writer, artefact); + } + + @Override + protected String getName() { + return XmlConstants.DATA_CONSTRAINT; + } + + @Override + protected String getNamePlural() { + return XmlConstants.DATA_CONSTRAINTS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getDataConstraints(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataConsumerSchemeWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataConsumerSchemeWriter.java new file mode 100644 index 0000000..850d2d6 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataConsumerSchemeWriter.java @@ -0,0 +1,69 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumer; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerScheme; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; + + +public class DataConsumerSchemeWriter extends XmlWriter { + + private final OrganisationWriter organisationWriter; + + public DataConsumerSchemeWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + OrganisationWriter organisationWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.organisationWriter = organisationWriter; + } + + @Override + protected void writeAttributes(DataConsumerScheme dataConsumerScheme, XMLStreamWriter writer) throws XMLStreamException { + DataConsumerSchemeImpl dataConsumerSchemeImpl = (DataConsumerSchemeImpl) dataConsumerScheme; + dataConsumerSchemeImpl.setVersion(Version.createFromString(XmlConstants.DEFAULT_VERSION)); + commonAttributesWriter.writeAttributes( + XmlConstants.DATA_CONSUMERS, + dataConsumerScheme.getOrganizationId(), + dataConsumerScheme.getUri(), + dataConsumerSchemeImpl.getUrn(), + null, + dataConsumerScheme.isExternalReference(), + dataConsumerScheme.getServiceUrl(), + dataConsumerScheme.getStructureUrl(), + dataConsumerScheme.getValidToString(), + dataConsumerScheme.getValidFromString(), + writer + ); + writer.writeAttribute(XmlConstants.IS_PARTIAL, String.valueOf(dataConsumerScheme.isPartial())); + } + + @Override + protected void writeCustomAttributeElements(DataConsumerScheme dataConsumerScheme, XMLStreamWriter writer) throws XMLStreamException { + List dataConsumerSchemeItems = dataConsumerScheme.getItems(); + organisationWriter.writeOrganisation(dataConsumerSchemeItems, writer, XmlConstants.DATA_CONSUMER); + } + + @Override + protected String getName() { + return XmlConstants.DATA_CONSUMER_SCHEME; + } + + @Override + protected String getNamePlural() { + return XmlConstants.DATA_CONSUMER_SCHEMES; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getDataConsumerSchemes(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataProviderSchemeWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataProviderSchemeWriter.java new file mode 100644 index 0000000..b6d53a1 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataProviderSchemeWriter.java @@ -0,0 +1,70 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataProvider; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderScheme; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; + + +public class DataProviderSchemeWriter extends XmlWriter { + + private final OrganisationWriter organisationWriter; + + public DataProviderSchemeWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + OrganisationWriter organisationWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.organisationWriter = organisationWriter; + } + + @Override + protected void writeAttributes(DataProviderScheme dataProviderScheme, XMLStreamWriter writer) throws XMLStreamException { + DataProviderSchemeImpl dataProviderSchemeImpl = (DataProviderSchemeImpl) dataProviderScheme; + dataProviderSchemeImpl.setVersion(Version.createFromString(XmlConstants.DEFAULT_VERSION)); + commonAttributesWriter.writeAttributes( + XmlConstants.DATA_PROVIDERS, + dataProviderScheme.getOrganizationId(), + dataProviderScheme.getUri(), + dataProviderSchemeImpl.getUrn(), + null, + dataProviderScheme.isExternalReference(), + dataProviderScheme.getServiceUrl(), + dataProviderScheme.getStructureUrl(), + dataProviderScheme.getValidToString(), + dataProviderScheme.getValidFromString(), + writer + ); + writer.writeAttribute(XmlConstants.IS_PARTIAL, String.valueOf(dataProviderScheme.isPartial())); + } + + @Override + protected void writeCustomAttributeElements(DataProviderScheme dataProviderScheme, XMLStreamWriter writer) throws XMLStreamException { + List dataProviderSchemeItems = dataProviderScheme.getItems(); + organisationWriter.writeOrganisation(dataProviderSchemeItems, writer, XmlConstants.DATA_PROVIDER); + } + + + @Override + protected String getName() { + return XmlConstants.DATA_PROVIDER_SCHEME; + } + + @Override + protected String getNamePlural() { + return XmlConstants.DATA_PROVIDER_SCHEMES; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getDataProviderSchemes(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataStructureDefinitionWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataStructureDefinitionWriter.java new file mode 100644 index 0000000..7de64ff --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataStructureDefinitionWriter.java @@ -0,0 +1,97 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.writer.XmlWriterUtils.writeCharacters; + +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinition; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.serializer.common.TimeDimensionLocalRepresentationAdapter; + +import org.apache.commons.collections4.CollectionUtils; + +public class DataStructureDefinitionWriter extends XmlWriter { + + private final AttributeListWriter attributeListWriter; + private final DimensionListWriter dimensionListWriter; + private final MeasureListWriter measureListWriter; + private final GroupDimensionListWriter groupDimensionListWriter; + private final TimeDimensionLocalRepresentationAdapter timeDimensionLocalRepresentationAdapter; + + public DataStructureDefinitionWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + AttributeListWriter attributeListWriter, + DimensionListWriter dimensionListWriter, + MeasureListWriter measureListWriter, + GroupDimensionListWriter groupDimensionListWriter, + TimeDimensionLocalRepresentationAdapter timeDimensionLocalRepresentationAdapter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.attributeListWriter = attributeListWriter; + this.dimensionListWriter = dimensionListWriter; + this.measureListWriter = measureListWriter; + this.groupDimensionListWriter = groupDimensionListWriter; + this.timeDimensionLocalRepresentationAdapter = timeDimensionLocalRepresentationAdapter; + } + + @Override + public void write(MaintainableArtefact maintainableArtefact, XMLStreamWriter writer) throws XMLStreamException { + DataStructureDefinition artefact = (DataStructureDefinition) maintainableArtefact; + artefact = timeDimensionLocalRepresentationAdapter.adapt(artefact); + super.write(artefact, writer); + } + + @Override + protected void writeAttributes(DataStructureDefinition dsd, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(dsd, writer); + } + + @Override + protected void writeCustomAttributeElements(DataStructureDefinition dsd, XMLStreamWriter writer) throws XMLStreamException { + writeDataStructureComponents(dsd, writer); + ArtefactReference metadataStructure = dsd.getMetadataStructure(); + if (metadataStructure != null) { + writeMetadata(metadataStructure, writer); + } + } + + @Override + protected String getName() { + return XmlConstants.DATA_STRUCTURE; + } + + @Override + protected String getNamePlural() { + return XmlConstants.DATA_STRUCTURES; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getDataStructures(); + } + + private void writeDataStructureComponents(DataStructureDefinition dsd, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(dsd.getComponents())) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.DATA_STRUCTURE_COMPONENTS); + dimensionListWriter.writeDimensionList(dsd.getDimensionDescriptor(), writer); + groupDimensionListWriter.writeGroupDimensionList(dsd.getGroupDimensionDescriptors(), writer); + attributeListWriter.writeAttributeList(dsd.getAttributeDescriptor(), writer); + measureListWriter.writeMeasureList(dsd.getMeasureDescriptor(), writer); + writer.writeEndElement(); + } + } + + private void writeMetadata(ArtefactReference metadataStructure, XMLStreamWriter writer) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.METADATA); + if (metadataStructure != null) { + writeCharacters(metadataStructure.getUrn(), writer); + } + writer.writeEndElement(); + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataflowWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataflowWriter.java new file mode 100644 index 0000000..2ad3a9c --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DataflowWriter.java @@ -0,0 +1,50 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Dataflow; + +public class DataflowWriter extends XmlWriter { + + public DataflowWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + } + + @Override + protected void writeAttributes(Dataflow dataflow, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(dataflow, writer); + } + + @Override + protected void writeCustomAttributeElements(Dataflow dataflow, XMLStreamWriter writer) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.STRUCTURE_UPPER); + ArtefactReference structure = dataflow.getStructure(); + if (structure != null) { + XmlWriterUtils.writeCharacters(structure.getUrn(), writer); + } + writer.writeEndElement(); + } + + @Override + protected String getName() { + return XmlConstants.DATAFLOW; + } + + @Override + protected String getNamePlural() { + return XmlConstants.DATAFLOWS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getDataflows(); + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DimensionListWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DimensionListWriter.java new file mode 100644 index 0000000..05f7e6a --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/DimensionListWriter.java @@ -0,0 +1,99 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Dimension; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponent; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.infomodel.sdmx30.TimeDimension; + +import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; + +@AllArgsConstructor +public class DimensionListWriter { + private final AnnotableWriter annotableWriter; + private final RepresentationWriter representationWriter; + + public void writeDimensionList(DimensionDescriptor dimensionDescriptor, XMLStreamWriter writer) throws XMLStreamException { + if (dimensionDescriptor != null) { + List components = dimensionDescriptor.getComponents(); + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.DIMENSION_LIST); + XmlWriterUtils.writeIdUriAttributes(writer, XmlConstants.DIMENSION_DESCRIPTOR_ID, dimensionDescriptor.getUri()); + if (dimensionDescriptor.getContainer() != null) { + XmlWriterUtils.writeUrn(dimensionDescriptor.getUrn(), writer); + } + annotableWriter.write(dimensionDescriptor, writer); + if (CollectionUtils.isNotEmpty(components)) { + List timeDimension = components.stream().filter(DimensionComponent::isTimeDimension).collect(Collectors.toList()); + List dimensions = (List) CollectionUtils.subtract(components, timeDimension); + writeDimensions(writer, dimensions); + writeTimeDimensions(writer, timeDimension); + } + writer.writeEndElement(); + } + + } + + private void writeTimeDimensions(XMLStreamWriter writer, List timeDimensionComponents) throws XMLStreamException { + List timeDimensions = Optional.ofNullable(timeDimensionComponents) + .stream() + .flatMap(List::stream) + .filter(d -> TimeDimension.class.isAssignableFrom(d.getClass())) + .map(TimeDimension.class::cast) + .collect(Collectors.toList()); + + if (CollectionUtils.isNotEmpty(timeDimensions)) { + for (TimeDimension timeDimension : timeDimensions) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.TIME_DIMENSION); + XmlWriterUtils.writeIdUriAttributes(writer, timeDimension.getId(), timeDimension.getUri()); + if (timeDimension.getContainer() != null) { + XmlWriterUtils.writeUrn(timeDimension.getUrn(), writer); + } + + this.annotableWriter.write(timeDimension, writer); + XmlWriterUtils.writeConceptIdentity(writer, timeDimension); + Representation localRepresentation = timeDimension.getLocalRepresentation(); + if (localRepresentation != null) { + representationWriter.writeRepresentation(writer, localRepresentation, "LocalRepresentation"); + } + writer.writeEndElement(); + } + } + } + + private void writeDimensions(XMLStreamWriter writer, List dimensionComponents) throws XMLStreamException { + List dimensions = Optional.ofNullable(dimensionComponents) + .stream() + .flatMap(List::stream) + .filter(d -> Dimension.class.isAssignableFrom(d.getClass())) + .map(Dimension.class::cast) + .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(dimensions)) { + for (Dimension dimension : dimensions) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.DIMENSION); + XmlWriterUtils.writeIdUriAttributes(writer, dimension.getId(), dimension.getUri()); + if (dimension.getContainer() != null) { + XmlWriterUtils.writeUrn(dimension.getUrn(), writer); + } + writer.writeAttribute(XmlConstants.POSITION, String.valueOf(dimension.getOrder())); + this.annotableWriter.write(dimension, writer); + XmlWriterUtils.writeConceptIdentity(writer, dimension); + Representation localRepresentation = dimension.getLocalRepresentation(); + if (localRepresentation != null) { + representationWriter.writeRepresentation(writer, localRepresentation, XmlConstants.LOCAL_REPRESENTATION); + } + List conceptRoles = dimension.getConceptRoles(); + XmlWriterUtils.writeConceptRoles(writer, conceptRoles); + writer.writeEndElement(); + } + } + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GeoFeatureSetCodeWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GeoFeatureSetCodeWriter.java new file mode 100644 index 0000000..78bcfd9 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GeoFeatureSetCodeWriter.java @@ -0,0 +1,22 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCodeImpl; + +public class GeoFeatureSetCodeWriter extends CodeWriter { + + protected GeoFeatureSetCodeWriter(UrnWriter urnWriter, NameableWriter nameableWriter, AnnotableWriter annotableWriter) { + super(urnWriter, nameableWriter, annotableWriter); + } + + @Override + public void writeAttributes(GeoFeatureSetCodeImpl code, XMLStreamWriter writer) throws XMLStreamException { + super.writeAttributes(code, writer); + String value = code.getValue(); + if (value != null) { + writer.writeAttribute(XmlConstants.VALUE_LOWER, value); + } + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GeoGridCodelistWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GeoGridCodelistWriter.java new file mode 100644 index 0000000..5645018 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GeoGridCodelistWriter.java @@ -0,0 +1,98 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.GeoGridCodelist; +import com.epam.jsdmx.infomodel.sdmx30.GridCode; +import com.epam.jsdmx.infomodel.sdmx30.SdmxUrn; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; + +import org.apache.commons.collections.CollectionUtils; + +public class GeoGridCodelistWriter extends XmlWriter { + + private final CodeListExtensionWriter codeListExtensionWriter; + private final GridCodeWriter gridCodeWriter; + + protected GeoGridCodelistWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + CodeListExtensionWriter codeListExtensionWriter, + GridCodeWriter gridCodeWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.codeListExtensionWriter = codeListExtensionWriter; + this.gridCodeWriter = gridCodeWriter; + } + + @Override + protected void writeAttributes(GeoGridCodelist geoGridCodelist, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes( + geoGridCodelist.getId(), + geoGridCodelist.getOrganizationId(), + geoGridCodelist.getUri(), + SdmxUrn.toFullUrnString( + StructureClassImpl.CODELIST, + geoGridCodelist.getOrganizationId(), + geoGridCodelist.getId(), + geoGridCodelist.getVersion() + ), + geoGridCodelist.getVersion(), + geoGridCodelist.isExternalReference(), + geoGridCodelist.getServiceUrl(), + geoGridCodelist.getStructureUrl(), + geoGridCodelist.getValidToString(), + geoGridCodelist.getValidFromString(), + writer + ); + writer.writeAttribute(XmlConstants.IS_PARTIAL, String.valueOf(geoGridCodelist.isPartial())); + writer.writeAttribute(XmlConstants.GEO_TYPE, XmlConstants.GEOGRID_CODELIST_TYPE); + } + + @Override + protected void writeCustomAttributeElements(GeoGridCodelist geoGridCodelist, XMLStreamWriter writer) throws XMLStreamException { + List codelistExtensions = geoGridCodelist.getExtensions(); + codeListExtensionWriter.writeCodeListExtensions(writer, codelistExtensions); + + String gridDefinition = geoGridCodelist.getGridDefinition(); + if (gridDefinition != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.GRID_DEFINITION); + writer.writeCharacters(gridDefinition); + writer.writeEndElement(); + } + + List geoGridCodelistItems = geoGridCodelist.getItems(); + if (CollectionUtils.isNotEmpty(geoGridCodelistItems)) { + for (GridCode gridCode : geoGridCodelistItems) { + if (gridCode != null) { + gridCodeWriter.write( + gridCode, + writer, + XmlConstants.GEO_GRID_CODES + ); + } + } + } + } + + @Override + protected String getName() { + return XmlConstants.GEOGRID_CODELIST; + } + + @Override + protected String getNamePlural() { + return XmlConstants.GEOGRID_CODELISTS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getGeoGridCodelists(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GeographicCodelistWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GeographicCodelistWriter.java new file mode 100644 index 0000000..be120ab --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GeographicCodelistWriter.java @@ -0,0 +1,96 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCode; +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeographicCodelist; +import com.epam.jsdmx.infomodel.sdmx30.SdmxUrn; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; + +import org.apache.commons.collections.CollectionUtils; + +public class GeographicCodelistWriter extends XmlWriter { + + private final GeoFeatureSetCodeWriter geoFeatureSetCodeWriter; + private final CodeListExtensionWriter codeListExtensionWriter; + + protected GeographicCodelistWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + GeoFeatureSetCodeWriter geoFeatureSetCodeWriter, + CodeListExtensionWriter codeListExtensionWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.geoFeatureSetCodeWriter = geoFeatureSetCodeWriter; + this.codeListExtensionWriter = codeListExtensionWriter; + } + + @Override + protected void writeAttributes(GeographicCodelist geographicCodelist, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes( + geographicCodelist.getId(), + geographicCodelist.getOrganizationId(), + geographicCodelist.getUri(), + SdmxUrn.toFullUrnString( + StructureClassImpl.CODELIST, + geographicCodelist.getOrganizationId(), + geographicCodelist.getId(), + geographicCodelist.getVersion() + ), + geographicCodelist.getVersion(), + geographicCodelist.isExternalReference(), + geographicCodelist.getServiceUrl(), + geographicCodelist.getStructureUrl(), + geographicCodelist.getValidToString(), + geographicCodelist.getValidFromString(), + writer + ); + writer.writeAttribute(XmlConstants.IS_PARTIAL, String.valueOf(geographicCodelist.isPartial())); + writer.writeAttribute(XmlConstants.GEO_TYPE, XmlConstants.GEOGRAPHIC_CODELIST); + } + + @Override + protected void writeCustomAttributeElements(GeographicCodelist geographicCodelist, XMLStreamWriter writer) throws XMLStreamException { + writeGeoFeatureCodelists(writer, geographicCodelist); + + List codelistExtensions = geographicCodelist.getExtensions(); + codeListExtensionWriter.writeCodeListExtensions(writer, codelistExtensions); + } + + private void writeGeoFeatureCodelists(XMLStreamWriter writer, GeographicCodelist geographicCodelist) throws XMLStreamException { + List geographicCodelistItems = geographicCodelist.getItems(); + if (CollectionUtils.isNotEmpty(geographicCodelistItems)) { + for (GeoFeatureSetCode geoFeatureSetCode : geographicCodelistItems) { + if (geoFeatureSetCode != null) { + geoFeatureSetCodeWriter.write( + (GeoFeatureSetCodeImpl) geoFeatureSetCode, + writer, + XmlConstants.GEO_FEATURE_SET_CODE + ); + } + } + } + } + + @Override + protected String getName() { + return XmlConstants.GEO_CODELIST; + } + + @Override + protected String getNamePlural() { + return XmlConstants.GEO_CODELISTS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getGeographicCodelists(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GridCodeWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GridCodeWriter.java new file mode 100644 index 0000000..f1f57d4 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GridCodeWriter.java @@ -0,0 +1,25 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.GridCode; + +public class GridCodeWriter extends CodeWriter { + + protected GridCodeWriter(UrnWriter urnWriter, NameableWriter nameableWriter, AnnotableWriter annotableWriter) { + super(urnWriter, nameableWriter, annotableWriter); + } + + @Override + public void writeElements(GridCode code, + XMLStreamWriter writer) throws XMLStreamException { + super.writeElements(code, writer); + String geoCell = code.getGeoCell(); + if (geoCell != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.GEO_CELL); + writer.writeCharacters(geoCell); + writer.writeEndElement(); + } + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GroupDimensionListWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GroupDimensionListWriter.java new file mode 100644 index 0000000..83ccbfd --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/GroupDimensionListWriter.java @@ -0,0 +1,45 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.GroupDimensionDescriptor; + +import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; + +@AllArgsConstructor +public class GroupDimensionListWriter { + + private final AnnotableWriter annotableWriter; + + public void writeGroupDimensionList(List groupDimensionDescriptor, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isEmpty(groupDimensionDescriptor)) { + return; + } + + for (GroupDimensionDescriptor groupDimension : groupDimensionDescriptor) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.GROUP); + XmlWriterUtils.writeIdUriAttributes(writer, groupDimension.getId(), groupDimension.getUri()); + + this.annotableWriter.write(groupDimension, writer); + List groupDimensions = groupDimension.getDimensions(); + if (CollectionUtils.isNotEmpty(groupDimensions)) { + for (String groupDimensionName : groupDimensions) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.GROUP_DIMENSION); + writeDimensionReference(writer, groupDimensionName); + writer.writeEndElement(); + } + } + writer.writeEndElement(); + } + } + + public void writeDimensionReference(XMLStreamWriter writer, String groupDimensionName) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.DIMENSION_REFERENCE); + XmlWriterUtils.writeCharacters(groupDimensionName, writer); + writer.writeEndElement(); + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/HeaderWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/HeaderWriter.java new file mode 100644 index 0000000..0ba5723 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/HeaderWriter.java @@ -0,0 +1,81 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.time.Instant; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultHeaderProvider; +import com.epam.jsdmx.serializer.sdmx30.common.Header; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.apache.commons.collections4.CollectionUtils; + +@AllArgsConstructor +@Getter +public class HeaderWriter { + + DefaultHeaderProvider defaultHeaderProvider; + + public void writeDefaultHeader(XMLStreamWriter writer) throws XMLStreamException { + Header header = defaultHeaderProvider.provide(); + write(writer, header); + } + + public void write(XMLStreamWriter writer, Header header) throws XMLStreamException { + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.HEADER); + writeHeaderElements(writer, header); + writer.writeEndElement(); + } + + public void writeHeaderElements(XMLStreamWriter writer, Header header) throws XMLStreamException { + String id = header.getId(); + if (id != null) { + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.MES_ID); + writer.writeCharacters(id); + writer.writeEndElement(); + } + + boolean test = header.isTest(); + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.MES_TEST); + writer.writeCharacters(String.valueOf(test)); + writer.writeEndElement(); + + Instant prepared = header.getPrepared(); + if (prepared != null) { + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.PREPARED); + writer.writeCharacters(prepared.toString()); + writer.writeEndElement(); + } + + Party sender = header.getSender(); + if (sender != null) { + String senderId = sender.getId(); + if (senderId != null) { + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.SENDER); + writer.writeAttribute(XmlConstants.ID, senderId); + InternationalString name = header.getName(); + XmlWriterUtils.writeInternationalString(name, writer, XmlConstants.COMMON + XmlConstants.COM_NAME); + writer.writeEndElement(); + } + } + + List receivers = header.getReceivers(); + if (CollectionUtils.isNotEmpty(receivers)) { + for (Party receiver : receivers) { + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.RECEIVER); + String receiverId = receiver.getId(); + if (receiverId != null) { + writer.writeAttribute(XmlConstants.ID, receiverId); + } + InternationalString name = header.getName(); + XmlWriterUtils.writeInternationalString(name, writer, XmlConstants.COMMON + XmlConstants.COM_NAME); + writer.writeEndElement(); + } + } + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/HierarchyAssociationWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/HierarchyAssociationWriter.java new file mode 100644 index 0000000..85cb939 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/HierarchyAssociationWriter.java @@ -0,0 +1,66 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.writer.XmlWriterUtils.writeCharacters; + +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyAssociation; + +public class HierarchyAssociationWriter extends XmlWriter { + + public HierarchyAssociationWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + } + + @Override + protected void writeAttributes(HierarchyAssociation hierarchyAssociation, XMLStreamWriter writer) throws XMLStreamException { + commonAttributesWriter.writeAttributes(hierarchyAssociation, writer); + } + + @Override + protected void writeCustomAttributeElements(HierarchyAssociation artefact, XMLStreamWriter writer) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.LINKED_HIERARCHY); + ArtefactReference linkedHierarchy = artefact.getLinkedHierarchy(); + if (linkedHierarchy != null) { + writeCharacters(linkedHierarchy.getUrn(), writer); + } + writer.writeEndElement(); + + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.LINKED_OBJECT); + ArtefactReference linkedObject = artefact.getLinkedObject(); + if (linkedObject != null) { + writeCharacters(linkedObject.getUrn(), writer); + } + writer.writeEndElement(); + + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CONTEXT_OBJECT); + ArtefactReference contextObject = artefact.getContextObject(); + if (contextObject != null) { + writeCharacters(contextObject.getUrn(), writer); + } + writer.writeEndElement(); + } + + @Override + protected String getName() { + return XmlConstants.HIERARCHY_ASSOCIATION; + } + + @Override + protected String getNamePlural() { + return XmlConstants.HIERARCHY_ASSOCIATIONS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getHierarchyAssociations(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/HierarchyWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/HierarchyWriter.java new file mode 100644 index 0000000..da13138 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/HierarchyWriter.java @@ -0,0 +1,139 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.net.URI; +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CodingFormat; +import com.epam.jsdmx.infomodel.sdmx30.Facet; +import com.epam.jsdmx.infomodel.sdmx30.HierarchicalCode; +import com.epam.jsdmx.infomodel.sdmx30.Hierarchy; +import com.epam.jsdmx.infomodel.sdmx30.Level; + +import org.apache.commons.collections4.CollectionUtils; + + +public class HierarchyWriter extends XmlWriter { + + private final UrnWriter urnWriter; + + public HierarchyWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + UrnWriter urnWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.urnWriter = urnWriter; + } + + @Override + protected void writeAttributes(Hierarchy hierarchy, XMLStreamWriter writer) throws XMLStreamException { + commonAttributesWriter.writeAttributes(hierarchy, writer); + boolean hasFormalLevels = hierarchy.isHasFormalLevels(); + writer.writeAttribute(XmlConstants.HAS_FORMAL_LEVELS, String.valueOf(hasFormalLevels)); + } + + @Override + protected void writeCustomAttributeElements(Hierarchy hierarchy, XMLStreamWriter writer) throws XMLStreamException { + writeLevel(hierarchy.getLevel(), writer); + writeHierarchicalCode(hierarchy.getCodes(), writer); + } + + @Override + protected String getName() { + return XmlConstants.HIERARCHY; + } + + @Override + protected String getNamePlural() { + return XmlConstants.HIERARCHIES; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getHierarchies(); + } + + private void writeHierarchicalCode(List codes, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(codes)) { + for (HierarchicalCode code : codes) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.HIERARCHICAL_CODE); + writeHierarchicalCode(writer, code); + writer.writeEndElement(); + } + } + } + + private void writeHierarchicalCode(XMLStreamWriter writer, HierarchicalCode code) throws XMLStreamException { + + XmlWriterUtils.writeUri(code.getUri(), writer); + + if (code.getContainer() != null) { + XmlWriterUtils.writeUrn(code.getUrn(), writer); + } + + XmlWriterUtils.writeInstant(code.getValidTo(), writer, XmlConstants.VALID_TO); + XmlWriterUtils.writeInstant(code.getValidFrom(), writer, XmlConstants.VALID_FROM); + + XmlWriterUtils.writeMandatoryAttribute(code.getId(), writer, XmlConstants.ID); + + annotableWriter.write(code, writer); + ArtefactReference codeRef = code.getCode(); + if (codeRef != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CODE); + urnWriter.writeUrnCharacters(codeRef, writer); + writer.writeEndElement(); + } + + String levelId = code.getLevelId(); + if (levelId != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.LEVEL); + writer.writeCharacters(levelId); + writer.writeEndElement(); + } + + List hierarchicalCodes = code.getHierarchicalCodes(); + if (CollectionUtils.isNotEmpty(hierarchicalCodes)) { + writeHierarchicalCode(hierarchicalCodes, writer); + } + } + + private void writeLevel(Level level, XMLStreamWriter writer) throws XMLStreamException { + if (level != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.LEVEL); + writer.writeAttribute(XmlConstants.ID, level.getId()); + + if (level.getContainer() != null) { + writer.writeAttribute(XmlConstants.URN, level.getUrn()); + } + + URI uri = level.getUri(); + if (uri != null) { + writer.writeAttribute(XmlConstants.URI, uri.toString()); + } + annotableWriter.write(level, writer); + nameableWriter.write(level, writer); + List codeFormat = level.getCodeFormat(); + if (CollectionUtils.isNotEmpty(codeFormat)) { + CodingFormat codingFormat = codeFormat.get(0); + Facet codingFormatInside = codingFormat.getCodingFormat(); + if (codingFormatInside != null && codingFormatInside.getType() != null) { + String value = XmlConstants.MAP_FACET_TYPE.get(codingFormatInside.getType().name()); + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CODING_FORMAT); + writer.writeAttribute(value, codingFormatInside.getValue()); + writer.writeEndElement(); + } + } + Level child = level.getChild(); + if (child != null && child.getId() != null) { + writeLevel(child, writer); + } + writer.writeEndElement(); + } + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ItemSchemeMapWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ItemSchemeMapWriter.java new file mode 100644 index 0000000..1af692b --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ItemSchemeMapWriter.java @@ -0,0 +1,65 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; + +import org.apache.commons.collections.CollectionUtils; + +public class ItemSchemeMapWriter { + + private final UrnWriter urnWriter; + + public ItemSchemeMapWriter(UrnWriter urnWriter) { + this.urnWriter = urnWriter; + } + + public void writeItems(XMLStreamWriter writer, List itemMaps, AnnotableWriter annotableWriter) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(itemMaps)) { + for (ItemMap itemMap : itemMaps) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.ITEM_MAP); + + writer.writeAttribute(XmlConstants.VALID_TO, XmlWriterUtils.instantToDateString(itemMap.getValidTo())); + writer.writeAttribute(XmlConstants.VALID_FROM, XmlWriterUtils.instantToDateString(itemMap.getValidFrom())); + annotableWriter.write(itemMap, writer); + + String source = itemMap.getSource(); + writeSource(writer, source, XmlConstants.STRUCTURE + XmlConstants.SOURCE_VALUE); + + String target = itemMap.getTarget(); + writeTarget(writer, target, XmlConstants.STRUCTURE + XmlConstants.TARGET_VALUE); + + writer.writeEndElement(); + } + } + } + + public void writeTarget(XMLStreamWriter writer, String target, String name) throws XMLStreamException { + writer.writeStartElement(name); + urnWriter.writeUrnCharacters(target, writer); + writer.writeEndElement(); + } + + public void writeTarget(XMLStreamWriter writer, ArtefactReference target, String name) throws XMLStreamException { + writer.writeStartElement(name); + urnWriter.writeUrnCharacters(target, writer); + writer.writeEndElement(); + } + + public void writeSource(XMLStreamWriter writer, String source, String name) throws XMLStreamException { + writer.writeStartElement(name); + urnWriter.writeUrnCharacters(source, writer); + writer.writeEndElement(); + } + + public void writeSource(XMLStreamWriter writer, ArtefactReference source, String name) throws XMLStreamException { + writer.writeStartElement(name); + urnWriter.writeUrnCharacters(source, writer); + writer.writeEndElement(); + } + +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/LinksWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/LinksWriter.java new file mode 100644 index 0000000..5819943 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/LinksWriter.java @@ -0,0 +1,21 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Link; + +public class LinksWriter { + + private final UrnWriter urnWriter; + + public LinksWriter(UrnWriter urnWriter) { + this.urnWriter = urnWriter; + } + + public void write(List links, XMLStreamWriter writer) throws XMLStreamException { + // Don't write links for sdmx 3.0 artefacts + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MeasureListWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MeasureListWriter.java new file mode 100644 index 0000000..1f3e927 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MeasureListWriter.java @@ -0,0 +1,58 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Measure; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.Representation; + +import lombok.AllArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; + +@AllArgsConstructor +public class MeasureListWriter { + + private final AnnotableWriter annotableWriter; + private final RepresentationWriter representationWriter; + + public void writeMeasureList(MeasureDescriptor measureDescriptor, XMLStreamWriter writer) throws XMLStreamException { + if (measureDescriptor != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.MEASURE_LIST); + XmlWriterUtils.writeIdUriAttributes( + writer, + XmlConstants.MEASURE_DESCRIPTOR_ID, + measureDescriptor.getUri() + ); + if (measureDescriptor.getContainer() != null) { + XmlWriterUtils.writeUrn(measureDescriptor.getUrn(), writer); + } + annotableWriter.write(measureDescriptor, writer); + List components = measureDescriptor.getComponents(); + writeMeasures(writer, components); + writer.writeEndElement(); + } + } + + private void writeMeasures(XMLStreamWriter writer, List components) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(components)) { + for (Measure measure : components) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.MEASURE); + XmlWriterUtils.writeIdUriAttributes(writer, measure.getId(), measure.getUri()); + if (measure.getContainer() != null) { + XmlWriterUtils.writeUrn(measure.getUrn(), writer); + } + annotableWriter.write(measure, writer); + XmlWriterUtils.writeConceptIdentity(writer, measure); + Representation localRepresentation = measure.getLocalRepresentation(); + if (localRepresentation != null) { + representationWriter.writeRepresentation(writer, localRepresentation, XmlConstants.LOCAL_REPRESENTATION); + } + XmlWriterUtils.writeConceptRoles(writer, measure.getConceptRoles()); + writer.writeEndElement(); + } + } + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MemberSelectionWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MemberSelectionWriter.java new file mode 100644 index 0000000..a94ad0d --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MemberSelectionWriter.java @@ -0,0 +1,143 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.writer.XmlWriterUtils.writeCharacters; + +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.AfterPeriod; +import com.epam.jsdmx.infomodel.sdmx30.BeforePeriod; +import com.epam.jsdmx.infomodel.sdmx30.CascadeValue; +import com.epam.jsdmx.infomodel.sdmx30.LocalisedMemberValue; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.MemberValue; +import com.epam.jsdmx.infomodel.sdmx30.MemberValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.RangePeriod; +import com.epam.jsdmx.infomodel.sdmx30.RangePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.SelectionValue; +import com.epam.jsdmx.infomodel.sdmx30.TimeRangePeriod; +import com.epam.jsdmx.infomodel.sdmx30.TimeRangeValue; + +import org.apache.commons.collections.CollectionUtils; + +public class MemberSelectionWriter { + + public void writeMemberSelections(XMLStreamWriter writer, List memberSelections) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(memberSelections)) { + for (MemberSelection memberSelection : memberSelections) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.COMPONENT); + + boolean includedMember = memberSelection.isIncluded(); + writer.writeAttribute(XmlConstants.INCLUDE, String.valueOf(includedMember)); + + String componentId = memberSelection.getComponentId(); + writer.writeAttribute(XmlConstants.ID, componentId); + + boolean removePrefix = memberSelection.isRemovePrefix(); + writer.writeAttribute(XmlConstants.REMOVE_PREFIX, String.valueOf(removePrefix)); + + List selectionValues = memberSelection.getSelectionValues(); + writeSelectionValues(writer, selectionValues); + + writer.writeEndElement(); + } + } + } + + public void writeSelectionValues(XMLStreamWriter writer, List selectionValues) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(selectionValues)) { + for (SelectionValue selectionValue : selectionValues) { + if (selectionValue instanceof MemberValue) { + writeMemberValue(writer, (MemberValueImpl) selectionValue); + } else if (selectionValue instanceof LocalisedMemberValue) { + writeLocalisedMemberValue(writer, (LocalisedMemberValue) selectionValue); + } else if (selectionValue instanceof TimeRangeValue) { + writeTimeRange(writer, selectionValue); + } + } + } + } + + private void writeLocalisedMemberValue(XMLStreamWriter writer, LocalisedMemberValue localisedMemberValue) throws XMLStreamException { + if (localisedMemberValue != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.VALUE); + + XmlWriterUtils.writeInstant(localisedMemberValue.getValidTo(), writer, XmlConstants.VALID_TO); + XmlWriterUtils.writeInstant(localisedMemberValue.getValidFrom(), writer, XmlConstants.VALID_FROM); + String locale = localisedMemberValue.getLocale(); + if (locale != null) { + writer.writeAttribute(XmlConstants.XML_LANG, locale); + } + + writeCharacters(localisedMemberValue.getValue(), writer); + + writer.writeEndElement(); + } + } + + private void writeTimeRange(XMLStreamWriter writer, SelectionValue selectionValue) throws XMLStreamException { + if (selectionValue != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.TIME_RANGE); + + XmlWriterUtils.writeInstant(selectionValue.getValidTo(), writer, XmlConstants.VALID_TO); + XmlWriterUtils.writeInstant(selectionValue.getValidFrom(), writer, XmlConstants.VALID_FROM); + + if (selectionValue instanceof BeforePeriod) { + BeforePeriod beforePeriod = (BeforePeriod) selectionValue; + writeTimeRangePeriod(writer, beforePeriod, XmlConstants.BEFORE_PERIOD); + } else if (selectionValue instanceof AfterPeriod) { + AfterPeriod afterPeriod = (AfterPeriod) selectionValue; + writeTimeRangePeriod(writer, afterPeriod, XmlConstants.AFTER_PERIOD); + } else if (selectionValue instanceof RangePeriod) { + RangePeriodImpl rangePeriod = (RangePeriodImpl) selectionValue; + writeRangePeriod(rangePeriod.getStartPeriod(), writer, XmlConstants.START_PERIOD); + writeRangePeriod(rangePeriod.getEndPeriod(), writer, XmlConstants.END_PERIOD); + } + + writer.writeEndElement(); + } + } + + private void writeRangePeriod(TimeRangePeriod rangePeriod, XMLStreamWriter writer, String periodName) throws XMLStreamException { + if (rangePeriod != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + periodName); + + writer.writeAttribute(XmlConstants.IS_INCLUSIVE, String.valueOf(rangePeriod.isInclusive())); + writeCharacters(rangePeriod.getPeriod(), writer); + + writer.writeEndElement(); + } + } + + private void writeMemberValue(XMLStreamWriter writer, MemberValueImpl memberVal) throws XMLStreamException { + if (memberVal != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.VALUE); + + XmlWriterUtils.writeInstant(memberVal.getValidTo(), writer, XmlConstants.VALID_TO); + XmlWriterUtils.writeInstant(memberVal.getValidFrom(), writer, XmlConstants.VALID_FROM); + CascadeValue cascadeValue = memberVal.getCascadeValue(); + if (cascadeValue != null) { + writer.writeAttribute(XmlConstants.CASCADE_VALUES, XmlConstants.CASCADE_VALUE_TYPE_STRING.get(cascadeValue)); + } + + writeCharacters(memberVal.getValue(), writer); + + writer.writeEndElement(); + } + } + + private void writeTimeRangePeriod(XMLStreamWriter writer, + TimeRangePeriod selectionValue, + String timeRangeName) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + timeRangeName); + + boolean inclusive = selectionValue.isInclusive(); + writer.writeAttribute(XmlConstants.IS_INCLUSIVE, String.valueOf(inclusive)); + + writeCharacters(selectionValue.getPeriod(), writer); + + writer.writeEndElement(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataConstraintWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataConstraintWriter.java new file mode 100644 index 0000000..5007b82 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataConstraintWriter.java @@ -0,0 +1,120 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.MetadataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.MetadataTargetRegion; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendar; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; + +import org.apache.commons.collections.CollectionUtils; + +public class MetadataConstraintWriter extends XmlWriter { + + private final ReleaseCalenderWriter releaseCalenderWriter; + private final MemberSelectionWriter memberSelectionWriter; + + public MetadataConstraintWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + ReleaseCalenderWriter releaseCalenderWriter, + MemberSelectionWriter memberSelectionWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.releaseCalenderWriter = releaseCalenderWriter; + this.memberSelectionWriter = memberSelectionWriter; + } + + @Override + protected void writeAttributes(MetadataConstraint metadataConstraint, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(metadataConstraint, writer); + writer.writeAttribute(XmlConstants.ROLE_ATTR, XmlConstants.ALLOWED); + } + + @Override + protected void writeCustomAttributeElements(MetadataConstraint metadataConstraint, XMLStreamWriter writer) throws XMLStreamException { + + List constrainedArtefacts = metadataConstraint.getConstrainedArtefacts(); + writeConstrainedArtefacts(writer, constrainedArtefacts); + + ReleaseCalendar releaseCalendar = metadataConstraint.getReleaseCalendar(); + releaseCalenderWriter.writeReleaseCalendar(writer, releaseCalendar); + + List metadataTargetRegions = metadataConstraint.getMetadataTargetRegions(); + writeMetadataTargetRegions(writer, metadataTargetRegions); + } + + private void writeConstrainedArtefacts(XMLStreamWriter writer, List constrainedArtefacts) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(constrainedArtefacts)) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CONSTRAINT_ATTACHMENT); + for (ArtefactReference constrained : constrainedArtefacts) { + writeConstrainedArtefact(writer, constrained); + } + writer.writeEndElement(); + } + } + + private void writeConstrainedArtefact(XMLStreamWriter writer, ArtefactReference constrained) throws XMLStreamException { + if (constrained != null) { + StructureClass maintainableStructureClass = constrained.getMaintainableStructureClass(); + String simpleName = maintainableStructureClass.getSimpleName(); + if (simpleName.equals(StructureClassImpl.METADATA_PROVIDER.getSimpleName())) { + XmlWriterUtils.writeArtefactReference(writer, XmlConstants.METADATA_PROVIDER, constrained.getUrn()); + } + if (simpleName.equals(StructureClassImpl.METADATA_SET.getSimpleName())) { + XmlWriterUtils.writeArtefactReference(writer, XmlConstants.METADATA_SET, constrained.getUrn()); + } + if (simpleName.equals(StructureClassImpl.METADATA_STRUCTURE.getSimpleName())) { + XmlWriterUtils.writeArtefactReference(writer, XmlConstants.METADATA_STRUCTURE, constrained.getUrn()); + } + if (simpleName.equals(StructureClassImpl.METADATAFLOW.getSimpleName())) { + XmlWriterUtils.writeArtefactReference(writer, XmlConstants.METADATAFLOW, constrained.getUrn()); + } + if (simpleName.equals(StructureClassImpl.METADATA_PROVISION_AGREEMENT.getSimpleName())) { + XmlWriterUtils.writeArtefactReference(writer, XmlConstants.METADATA_PROVISION_AGREEMENT, constrained.getUrn()); + } + } + } + + private void writeMetadataTargetRegions(XMLStreamWriter writer, List metadataTargetRegions) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(metadataTargetRegions)) { + for (MetadataTargetRegion metadataTargetRegion : metadataTargetRegions) { + if (metadataTargetRegion != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.METADATA_TARGET_REGION); + + boolean included = metadataTargetRegion.isIncluded(); + writer.writeAttribute(XmlConstants.INCLUDE, String.valueOf(included)); + XmlWriterUtils.writeInstant(metadataTargetRegion.getValidTo(), writer, XmlConstants.VALID_TO); + XmlWriterUtils.writeInstant(metadataTargetRegion.getValidFrom(), writer, XmlConstants.VALID_FROM); + List memberSelections = metadataTargetRegion.getMemberSelections(); + memberSelectionWriter.writeMemberSelections(writer, memberSelections); + + writer.writeEndElement(); + } + } + } + } + + @Override + protected String getName() { + return XmlConstants.METADATA_CONSTRAINT; + } + + @Override + protected String getNamePlural() { + return XmlConstants.METADATA_CONSTRAINTS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getMetadataConstraints(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataProviderSchemeWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataProviderSchemeWriter.java new file mode 100644 index 0000000..59c0959 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataProviderSchemeWriter.java @@ -0,0 +1,69 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProvider; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderScheme; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; + + +public class MetadataProviderSchemeWriter extends XmlWriter { + + private final OrganisationWriter organisationWriter; + + public MetadataProviderSchemeWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + OrganisationWriter organisationWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.organisationWriter = organisationWriter; + } + + @Override + protected void writeAttributes(MetadataProviderScheme metadataProviderScheme, XMLStreamWriter writer) throws XMLStreamException { + MetadataProviderSchemeImpl metadataProviderSchemeImpl = (MetadataProviderSchemeImpl) metadataProviderScheme; + metadataProviderSchemeImpl.setVersion(Version.createFromString(XmlConstants.DEFAULT_VERSION)); + commonAttributesWriter.writeAttributes( + XmlConstants.METADATA_PROVIDERS, + metadataProviderScheme.getOrganizationId(), + metadataProviderScheme.getUri(), + metadataProviderSchemeImpl.getUrn(), + null, + metadataProviderScheme.isExternalReference(), + metadataProviderScheme.getServiceUrl(), + metadataProviderScheme.getStructureUrl(), + metadataProviderScheme.getValidToString(), + metadataProviderScheme.getValidFromString(), + writer + ); + writer.writeAttribute(XmlConstants.IS_PARTIAL, String.valueOf(metadataProviderScheme.isPartial())); + } + + @Override + protected void writeCustomAttributeElements(MetadataProviderScheme dataProviderScheme, XMLStreamWriter writer) throws XMLStreamException { + List dataProviderSchemeItems = dataProviderScheme.getItems(); + organisationWriter.writeOrganisation(dataProviderSchemeItems, writer, XmlConstants.METADATA_PROVIDER); + } + + @Override + protected String getName() { + return XmlConstants.METADATA_PROVIDER_SCHEME; + } + + @Override + protected String getNamePlural() { + return XmlConstants.METADATA_PROVIDER_SCHEMES; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getMetadataProviderSchemes(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataProvisionAgreementWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataProvisionAgreementWriter.java new file mode 100644 index 0000000..1aeaab7 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataProvisionAgreementWriter.java @@ -0,0 +1,62 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.writer.XmlWriterUtils.writeCharacters; + +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProvisionAgreement; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; + +public class MetadataProvisionAgreementWriter extends XmlWriter { + + public MetadataProvisionAgreementWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + } + + @Override + protected void writeAttributes(MetadataProvisionAgreement artefact, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(artefact, writer); + } + + @Override + protected void writeCustomAttributeElements(MetadataProvisionAgreement metadataProvisionAgreement, XMLStreamWriter writer) throws XMLStreamException { + ArtefactReference controlledStructureUsage = metadataProvisionAgreement.getControlledStructureUsage(); + if (controlledStructureUsage != null + && controlledStructureUsage.getMaintainableStructureClass().equals(StructureClassImpl.METADATAFLOW)) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.METADATA_FLOW); + writeCharacters(controlledStructureUsage.getUrn(), writer); + writer.writeEndElement(); + } + + ArtefactReference metadataProvider = metadataProvisionAgreement.getMetadataProvider(); + if (metadataProvider != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.METADATA_PROVIDER); + writeCharacters(metadataProvider.getUrn(), writer); + writer.writeEndElement(); + } + + } + + @Override + protected String getName() { + return XmlConstants.METADATA_PROVISION_AGREEMENT; + } + + @Override + protected String getNamePlural() { + return XmlConstants.METADATA_PROVISION_AGREEMENTS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getMetadataProvisionAgreements(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataStructureDefinitionWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataStructureDefinitionWriter.java new file mode 100644 index 0000000..a3ebcb7 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataStructureDefinitionWriter.java @@ -0,0 +1,97 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttribute; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinition; + +import org.apache.commons.collections4.CollectionUtils; + +public class MetadataStructureDefinitionWriter extends XmlWriter { + + private final RepresentationWriter representationWriter; + + public MetadataStructureDefinitionWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + RepresentationWriter representationWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.representationWriter = representationWriter; + } + + @Override + protected void writeAttributes(MetadataStructureDefinition metadataStructureDefinition, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(metadataStructureDefinition, writer); + } + + @Override + protected void writeCustomAttributeElements(MetadataStructureDefinition metadataStructureDefinition, XMLStreamWriter writer) throws XMLStreamException { + writeMetadataStructureComponents(metadataStructureDefinition.getAttributeDescriptor(), writer); + } + + @Override + protected String getName() { + return XmlConstants.METADATA_STRUCTURE; + } + + @Override + protected String getNamePlural() { + return XmlConstants.METADATA_STRUCTURES; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getMetadataStructureDefinitions(); + } + + private void writeMetadataStructureComponents(MetadataAttributeDescriptor attributeDescriptor, XMLStreamWriter writer) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.METADATA_STRUCTURE_COMPONENTS); + if (attributeDescriptor != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.METADATA_ATTRIBUTE_LIST); + + if (attributeDescriptor.getContainer() != null) { + writer.writeAttribute(XmlConstants.URN, attributeDescriptor.getUrn()); + } + + this.annotableWriter.write(attributeDescriptor, writer); + List components = attributeDescriptor.getComponents(); + writeMetadataAttributes(writer, components); + + writer.writeEndElement(); + } + writer.writeEndElement(); + } + + private void writeMetadataAttributes(XMLStreamWriter writer, List components) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(components)) { + for (MetadataAttribute attribute : components) { + writeMetadataAttribute(attribute, writer); + } + } + } + + private void writeMetadataAttribute(MetadataAttribute attribute, XMLStreamWriter writer) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.METADATA_ATTRIBUTE); + XmlWriterUtils.writeIdUriAttributes(writer, attribute.getId(), attribute.getUri()); + if (attribute.getContainer() != null) { + writer.writeAttribute(XmlConstants.URN, attribute.getUrn()); + } + + writer.writeAttribute(XmlConstants.MIN_OCCURS, String.valueOf(attribute.getMinOccurs())); + writer.writeAttribute(XmlConstants.MAX_OCCURS, String.valueOf(attribute.getMaxOccurs())); + writer.writeAttribute(XmlConstants.IS_PRESENTATIONAL, String.valueOf(attribute.isPresentational())); + + this.annotableWriter.write(attribute, writer); + XmlWriterUtils.writeConceptIdentity(writer, attribute); + representationWriter.writeRepresentation(writer, attribute.getLocalRepresentation(), XmlConstants.LOCAL_REPRESENTATION); + writeMetadataAttributes(writer, attribute.getHierarchy()); + writer.writeEndElement(); + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataflowWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataflowWriter.java new file mode 100644 index 0000000..e10a552 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/MetadataflowWriter.java @@ -0,0 +1,74 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.writer.XmlConstants.STRUCTURE_UPPER; +import static com.epam.jsdmx.xml30.structure.writer.XmlWriterUtils.writeCharacters; + +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableObjectSelection; +import com.epam.jsdmx.infomodel.sdmx30.Metadataflow; + +import org.apache.commons.collections4.CollectionUtils; + +public class MetadataflowWriter extends XmlWriter { + + public MetadataflowWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + } + + @Override + protected void writeAttributes(Metadataflow metadataflow, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(metadataflow, writer); + } + + @Override + protected void writeCustomAttributeElements(Metadataflow metadataflow, XMLStreamWriter writer) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + STRUCTURE_UPPER); + ArtefactReference structure = metadataflow.getStructure(); + if (structure != null) { + writeCharacters(structure.getUrn(), writer); + } + writer.writeEndElement(); + + List selections = metadataflow.getSelections(); + if (CollectionUtils.isNotEmpty(selections)) { + List artefactReferences = selections.stream() + .filter(Objects::nonNull) + .flatMap(section -> section.getResolvesTo().stream()) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + for (ArtefactReference reference : artefactReferences) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.TARGET); + writeCharacters(reference.getUrn(), writer); + writer.writeEndElement(); + } + } + } + + @Override + protected String getName() { + return XmlConstants.METADATA_FLOW; + } + + @Override + protected String getNamePlural() { + return XmlConstants.METADATA_FLOWS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getMetadataflows(); + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/NameableWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/NameableWriter.java new file mode 100644 index 0000000..73517fd --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/NameableWriter.java @@ -0,0 +1,20 @@ +package com.epam.jsdmx.xml30.structure.writer; + + +import static com.epam.jsdmx.xml30.structure.writer.XmlWriterUtils.writeInternationalString; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.NameableArtefact; + +public class NameableWriter { + + public void write(NameableArtefact artefact, XMLStreamWriter writer) throws XMLStreamException { + InternationalString name = artefact.getName(); + writeInternationalString(name, writer, XmlConstants.COMMON + XmlConstants.COM_NAME); + InternationalString description = artefact.getDescription(); + writeInternationalString(description, writer, XmlConstants.COMMON + XmlConstants.COM_DESCRIPTION); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/OrganisationSchemeMapWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/OrganisationSchemeMapWriter.java new file mode 100644 index 0000000..8f3a415 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/OrganisationSchemeMapWriter.java @@ -0,0 +1,71 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationSchemeMap; + +public class OrganisationSchemeMapWriter extends XmlWriter { + + private final ItemSchemeMapWriter itemSchemeMapWriter; + private final UrnWriter urnWriter; + + public OrganisationSchemeMapWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + ItemSchemeMapWriter itemSchemeMapWriter, + UrnWriter urnWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.itemSchemeMapWriter = itemSchemeMapWriter; + this.urnWriter = urnWriter; + } + + @Override + protected void writeAttributes(OrganisationSchemeMap artefact, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(artefact, writer); + } + + @Override + protected void writeCustomAttributeElements(OrganisationSchemeMap organisationSchemeMap, XMLStreamWriter writer) throws XMLStreamException { + ArtefactReference source = organisationSchemeMap.getSource(); + writeArtefactReference(source, writer, XmlConstants.SOURCE); + + ArtefactReference target = organisationSchemeMap.getTarget(); + writeArtefactReference(target, writer, XmlConstants.TARGET); + + List itemMaps = organisationSchemeMap.getItemMaps(); + itemSchemeMapWriter.writeItems(writer, itemMaps, annotableWriter); + } + + private void writeArtefactReference(ArtefactReference artefactReference, + XMLStreamWriter writer, + String refName) throws XMLStreamException { + if (artefactReference != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + refName); + urnWriter.writeUrnCharacters(artefactReference, writer); + writer.writeEndElement(); + } + } + + @Override + protected String getName() { + return XmlConstants.ORGANISATION_SCHEME_MAP; + } + + @Override + protected String getNamePlural() { + return XmlConstants.ORGANISATION_SCHEME_MAPS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getOrganisationSchemeMaps(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/OrganisationUnitSchemeWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/OrganisationUnitSchemeWriter.java new file mode 100644 index 0000000..1634376 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/OrganisationUnitSchemeWriter.java @@ -0,0 +1,72 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnit; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitScheme; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; + +import org.apache.commons.collections.CollectionUtils; + +public class OrganisationUnitSchemeWriter extends XmlWriter { + + private final OrganisationWriter organisationWriter; + + public OrganisationUnitSchemeWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + OrganisationWriter organisationWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.organisationWriter = organisationWriter; + } + + @Override + protected void writeAttributes(OrganisationUnitScheme organisationUnitScheme, XMLStreamWriter writer) throws XMLStreamException { + OrganisationUnitSchemeImpl organisationUnitSchemeImpl = (OrganisationUnitSchemeImpl) organisationUnitScheme; + organisationUnitSchemeImpl.setVersion(Version.createFromString(XmlConstants.DEFAULT_VERSION)); + commonAttributesWriter.writeAttributes( + organisationUnitSchemeImpl.getId(), + organisationUnitSchemeImpl.getOrganizationId(), + organisationUnitSchemeImpl.getUri(), + organisationUnitSchemeImpl.getUrn(), + null, + organisationUnitSchemeImpl.isExternalReference(), + organisationUnitSchemeImpl.getServiceUrl(), + organisationUnitSchemeImpl.getStructureUrl(), + organisationUnitSchemeImpl.getValidToString(), + organisationUnitSchemeImpl.getValidFromString(), + writer + ); + writer.writeAttribute(XmlConstants.IS_PARTIAL, String.valueOf(organisationUnitSchemeImpl.isPartial())); + } + + @Override + protected void writeCustomAttributeElements(OrganisationUnitScheme organisationUnitScheme, XMLStreamWriter writer) throws XMLStreamException { + List organisationUnitSchemeItems = organisationUnitScheme.getItems(); + if (CollectionUtils.isNotEmpty(organisationUnitSchemeItems)) { + organisationWriter.writeOrganisation(organisationUnitSchemeItems, writer, XmlConstants.ORGANISATION_UNIT); + } + } + + @Override + protected String getName() { + return XmlConstants.ORGANISATION_UNIT_SCHEME; + } + + @Override + protected String getNamePlural() { + return XmlConstants.ORGANISATION_UNIT_SCHEMES; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getOrganisationUnitSchemes(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/OrganisationWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/OrganisationWriter.java new file mode 100644 index 0000000..ddf69c3 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/OrganisationWriter.java @@ -0,0 +1,67 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Contact; +import com.epam.jsdmx.infomodel.sdmx30.Organisation; + +import lombok.AllArgsConstructor; +import org.apache.commons.collections.CollectionUtils; + +@AllArgsConstructor +public class OrganisationWriter { + + private final ContactWriter contactWriter; + private final AnnotableWriter annotableWriter; + private final NameableWriter nameableWriter; + + > void writeOrganisation(List organisationItems, + XMLStreamWriter writer, + String name) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(organisationItems)) { + Map parentIdWithHierarchy = new HashMap<>(); + for (T organisat : organisationItems) { + List> children = organisat.getHierarchy(); + if (CollectionUtils.isNotEmpty(children)) { + for (Organisation child : children) { + parentIdWithHierarchy.put(child.getId(), organisat.getId()); + } + } + } + for (T organisation : organisationItems) { + writeOrganisation(writer, name, parentIdWithHierarchy, organisation); + } + } + } + + private > void writeOrganisation(XMLStreamWriter writer, + String name, Map parentIdWithHierarchy, + T organisation) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + name); + XmlWriterUtils.writeIdUriAttributes(writer, organisation.getId(), organisation.getUri()); + + if (organisation.getContainer() != null) { + XmlWriterUtils.writeUrn(organisation.getUrn(), writer); + } + + annotableWriter.write(organisation, writer); + nameableWriter.write(organisation, writer); + + List contacts = organisation.getContacts(); + contactWriter.writeContacts(contacts, writer); + + String organisationId = organisation.getId(); + if (parentIdWithHierarchy.containsKey(organisation.getId())) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.STRUCTURE_PARENT); + writer.writeCharacters(parentIdWithHierarchy.get(organisationId)); + writer.writeEndElement(); + } + + writer.writeEndElement(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ProcessWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ProcessWriter.java new file mode 100644 index 0000000..0466503 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ProcessWriter.java @@ -0,0 +1,185 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.writer.XmlWriterUtils.writeCharacters; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Computation; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.Process; +import com.epam.jsdmx.infomodel.sdmx30.ProcessArtefact; +import com.epam.jsdmx.infomodel.sdmx30.ProcessStep; +import com.epam.jsdmx.infomodel.sdmx30.Transition; + +import org.apache.commons.collections.CollectionUtils; + +public class ProcessWriter extends XmlWriter { + + public ProcessWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + } + + @Override + protected void writeAttributes(Process artefact, XMLStreamWriter writer) throws XMLStreamException { + commonAttributesWriter.writeAttributes(artefact, writer); + } + + @Override + protected void writeCustomAttributeElements(Process process, XMLStreamWriter writer) throws XMLStreamException { + List processSteps = process.getSteps(); + writeProcessSteps(writer, processSteps); + } + + private void writeProcessSteps(XMLStreamWriter writer, List processSteps) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(processSteps)) { + for (ProcessStep processStep : processSteps) { + if (processStep != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.PROCESS_STEP); + XmlWriterUtils.writeIdUriAttributes(writer, processStep.getId(), processStep.getUri()); + if (processStep.getContainer() != null) { + writer.writeAttribute(XmlConstants.URN, processStep.getUrn()); + } + + annotableWriter.write(processStep, writer); + nameableWriter.write(processStep, writer); + + List inputs = processStep.getInputs(); + writeInputOutput(writer, inputs, XmlConstants.INPUT); + + List outputs = processStep.getOutputs(); + writeInputOutput(writer, outputs, XmlConstants.OUTPUT); + + Computation computation = processStep.getComputation(); + writeComputation(computation, writer); + + List transitions = processStep.getTransitions(); + writeTransitions(writer, transitions); + + writeProcessSteps(writer, processStep.getChildren()); + writer.writeEndElement(); + } + } + } + } + + private void writeTransitions(XMLStreamWriter writer, List transitions) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(transitions)) { + for (Transition transition : transitions) { + if (transition != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.TRANSITION); + XmlWriterUtils.writeIdUriAttributes(writer, transition.getId(), transition.getUri()); + if (transition.getContainer() != null) { + writer.writeAttribute(XmlConstants.URN, transition.getUrn()); + } + + String localId = transition.getLocalId(); + if (localId != null) { + writer.writeAttribute(XmlConstants.LOCAL_ID, localId); + } + + annotableWriter.write(transition, writer); + + writeTargetProcessStep(writer, transition); + + writeCondition(writer, transition); + + writer.writeEndElement(); + } + } + } + } + + private void writeCondition(XMLStreamWriter writer, Transition transition) throws XMLStreamException { + InternationalString condition = transition.getCondition(); + XmlWriterUtils.writeInternationalString(condition, writer, XmlConstants.STRUCTURE + XmlConstants.CONDITION); + } + + private void writeTargetProcessStep(XMLStreamWriter writer, Transition transition) throws XMLStreamException { + String targetProcessStep = transition.getTargetProcessStep(); + if (targetProcessStep != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.TARGET_STEP); + writeCharacters(targetProcessStep, writer); + writer.writeEndElement(); + } + } + + private void writeInputOutput(XMLStreamWriter writer, List inputOutputs, String inputOutputName) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(inputOutputs)) { + for (ProcessArtefact inputOutput : inputOutputs) { + if (inputOutput != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + inputOutputName); + + String localId = inputOutput.getLocalId(); + if (localId != null) { + writer.writeAttribute(XmlConstants.LOCAL_ID, localId); + } + + annotableWriter.write(inputOutput, writer); + + ArtefactReference artefact = inputOutput.getArtefact(); + if (artefact != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.OBJECT_REFERENCE); + writeCharacters(artefact.getUrn(), writer); + writer.writeEndElement(); + } + + writer.writeEndElement(); + } + } + } + } + + private void writeComputation(Computation computation, XMLStreamWriter writer) throws XMLStreamException { + if (computation != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.COMPUTATION); + + String localId = computation.getLocalId(); + if (localId != null) { + writer.writeAttribute(XmlConstants.LOCAL_ID, localId); + } + + String softwareLanguage = computation.getSoftwareLanguage(); + if (softwareLanguage != null) { + writer.writeAttribute(XmlConstants.SOFTWARE_LANGUAGE, softwareLanguage); + } + + String softwareVersion = computation.getSoftwareVersion(); + if (softwareVersion != null) { + writer.writeAttribute(XmlConstants.SOFTWARE_VERSION, softwareVersion); + } + + String softwarePackage = computation.getSoftwarePackage(); + if (softwarePackage != null) { + writer.writeAttribute(XmlConstants.SOFTWARE_PACKAGE, softwarePackage); + } + + annotableWriter.write(computation, writer); + XmlWriterUtils.writeInternationalString(computation.getDescription(), writer, XmlConstants.COMMON + XmlConstants.DESCRIPTION); + writer.writeEndElement(); + } + } + + @Override + protected String getName() { + return XmlConstants.PROCESS; + } + + @Override + protected String getNamePlural() { + return XmlConstants.PROCESSES; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getProcesses(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ProvisionAgreementWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ProvisionAgreementWriter.java new file mode 100644 index 0000000..7799f6c --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ProvisionAgreementWriter.java @@ -0,0 +1,58 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ProvisionAgreement; + +public class ProvisionAgreementWriter extends XmlWriter { + + public ProvisionAgreementWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + } + + @Override + protected void writeAttributes(ProvisionAgreement provisionAgreement, XMLStreamWriter writer) throws XMLStreamException { + commonAttributesWriter.writeAttributes(provisionAgreement, writer); + } + + @Override + protected void writeCustomAttributeElements(ProvisionAgreement provisionAgreement, XMLStreamWriter writer) throws XMLStreamException { + ArtefactReference dataProvider = provisionAgreement.getDataProvider(); + ArtefactReference controlledStructureUsage = provisionAgreement.getControlledStructureUsage(); + + if (controlledStructureUsage != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.DATAFLOW); + XmlWriterUtils.writeCharacters(controlledStructureUsage.getUrn(), writer); + writer.writeEndElement(); + } + + if (dataProvider != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.DATA_PROVIDER); + XmlWriterUtils.writeCharacters(dataProvider.getUrn(), writer); + writer.writeEndElement(); + } + } + + @Override + protected String getName() { + return XmlConstants.PROVISION_AGREEMENT; + } + + @Override + protected String getNamePlural() { + return XmlConstants.PROVISION_AGREEMENTS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getProvisionAgreements(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ReleaseCalenderWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ReleaseCalenderWriter.java new file mode 100644 index 0000000..820e36b --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ReleaseCalenderWriter.java @@ -0,0 +1,36 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendar; + +public class ReleaseCalenderWriter { + + public void writeReleaseCalendar(XMLStreamWriter writer, ReleaseCalendar releaseCalendar) throws XMLStreamException { + if (releaseCalendar != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.RELEASE_CALENDAR); + + String periodicity = releaseCalendar.getPeriodicity(); + writeReleaseCalendarComponent(writer, periodicity, XmlConstants.PERIODICITY); + + String offset = releaseCalendar.getOffset(); + writeReleaseCalendarComponent(writer, offset, XmlConstants.OFFSET); + + String tolerance = releaseCalendar.getTolerance(); + writeReleaseCalendarComponent(writer, tolerance, XmlConstants.TOLERANCE); + + writer.writeEndElement(); + } + } + + private void writeReleaseCalendarComponent(XMLStreamWriter writer, + String component, + String componentName) throws XMLStreamException { + if (component != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + componentName); + writer.writeCharacters(component); + writer.writeEndElement(); + } + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyMapWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyMapWriter.java new file mode 100644 index 0000000..db2748e --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyMapWriter.java @@ -0,0 +1,50 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyMap; + +public class ReportingTaxonomyMapWriter extends XmlWriter { + + private final ItemSchemeMapWriter itemSchemeMapWriter; + + public ReportingTaxonomyMapWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + ItemSchemeMapWriter itemSchemeMapWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.itemSchemeMapWriter = itemSchemeMapWriter; + } + + @Override + protected void writeAttributes(ReportingTaxonomyMap reportingTaxonomyMap, XMLStreamWriter writer) throws XMLStreamException { + commonAttributesWriter.writeAttributes(reportingTaxonomyMap, writer); + } + + @Override + protected void writeCustomAttributeElements(ReportingTaxonomyMap reportingTaxonomyMap, XMLStreamWriter writer) throws XMLStreamException { + itemSchemeMapWriter.writeSource(writer, reportingTaxonomyMap.getSource(), XmlConstants.STRUCTURE + XmlConstants.SOURCE); + itemSchemeMapWriter.writeTarget(writer, reportingTaxonomyMap.getTarget(), XmlConstants.STRUCTURE + XmlConstants.TARGET); + itemSchemeMapWriter.writeItems(writer, reportingTaxonomyMap.getItemMaps(), annotableWriter); + } + + @Override + protected String getName() { + return XmlConstants.REPORTING_TAXONOMY_MAP; + } + + @Override + protected String getNamePlural() { + return XmlConstants.REPORTING_TAXONOMY_MAPS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getReportingTaxonomyMaps(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyWriter.java new file mode 100644 index 0000000..b03f491 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyWriter.java @@ -0,0 +1,93 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.writer.XmlWriterUtils.writeCharacters; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ReportingCategory; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomy; + +import org.apache.commons.collections.CollectionUtils; + +public class ReportingTaxonomyWriter extends XmlWriter { + + public ReportingTaxonomyWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + } + + @Override + protected void writeAttributes(ReportingTaxonomy reportingTaxonomy, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(reportingTaxonomy, writer); + writer.writeAttribute(XmlConstants.IS_PARTIAL, String.valueOf(reportingTaxonomy.isPartial())); + } + + @Override + protected void writeCustomAttributeElements(ReportingTaxonomy reportingTaxonomy, XMLStreamWriter writer) throws XMLStreamException { + List reportingTaxonomyItems = reportingTaxonomy.getItems(); + writeReportingCategory(writer, reportingTaxonomyItems); + + } + + private void writeReportingCategory(XMLStreamWriter writer, List reportingTaxonomyItems) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(reportingTaxonomyItems)) { + for (ReportingCategory reportingCategory : reportingTaxonomyItems) { + if (reportingCategory != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.REPORTING_CATEGORY); + XmlWriterUtils.writeIdUriAttributes(writer, reportingCategory.getId(), reportingCategory.getUri()); + if (reportingCategory.getContainer() != null) { + writer.writeAttribute(XmlConstants.URN, reportingCategory.getUrn()); + } + annotableWriter.write(reportingCategory, writer); + nameableWriter.write(reportingCategory, writer); + + List flows = reportingCategory.getFlows(); + writeArtefactReferences(flows, XmlConstants.STRUCTURE + XmlConstants.PROVISIONING_METADATA, writer); + + List structures = reportingCategory.getStructures(); + writeArtefactReferences(structures, XmlConstants.STRUCTURE + XmlConstants.STRUCTURAL_METADATA, writer); + + List hierarchy = (List) reportingCategory.getHierarchy(); + writeReportingCategory(writer, hierarchy); + + writer.writeEndElement(); + } + } + } + } + + private void writeArtefactReferences(List artefactReferences, String referenceName, XMLStreamWriter writer) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(artefactReferences)) { + for (ArtefactReference artefactReference : artefactReferences) { + if (artefactReference != null) { + writer.writeStartElement(referenceName); + writeCharacters(artefactReference.getUrn(), writer); + writer.writeEndElement(); + } + } + } + } + + @Override + protected String getName() { + return XmlConstants.REPORTING_TAXONOMY; + } + + @Override + protected String getNamePlural() { + return XmlConstants.REPORTING_TAXONOMIES; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getReportingTaxonomies(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/RepresentationMapWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/RepresentationMapWriter.java new file mode 100644 index 0000000..9a7463e --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/RepresentationMapWriter.java @@ -0,0 +1,152 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueTypeRepresentation; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueTypeRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.ListReferenceValueRepresentation; +import com.epam.jsdmx.infomodel.sdmx30.ListReferenceValueRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.MappedValue; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMap; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapping; +import com.epam.jsdmx.infomodel.sdmx30.TargetValue; +import com.epam.jsdmx.infomodel.sdmx30.ValueRepresentation; + +import org.apache.commons.collections4.CollectionUtils; + +public class RepresentationMapWriter extends XmlWriter { + + private final UrnWriter urnWriter; + + public RepresentationMapWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter, + UrnWriter urnWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + this.urnWriter = urnWriter; + } + + @Override + protected void writeAttributes(RepresentationMap representationMap, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(representationMap, writer); + } + + @Override + protected void writeCustomAttributeElements(RepresentationMap artefact, XMLStreamWriter writer) throws XMLStreamException { + List representationMappings = artefact.getRepresentationMappings(); + List target = artefact.getTarget(); + List source = artefact.getSource(); + + writeValueRepresentation(writer, source, XmlConstants.SOURCE_DATA_TYPE, XmlConstants.SOURCE_CODELIST); + writeValueRepresentation(writer, target, XmlConstants.TARGET_DATA_TYPE, XmlConstants.TARGET_CODELIST); + + writeRepresentationMappings(writer, representationMappings); + } + + @Override + protected String getName() { + return XmlConstants.REPRESENTATION_MAP; + } + + @Override + protected String getNamePlural() { + return XmlConstants.REPRESENTATION_MAPS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getRepresentationMaps(); + } + + private void writeValueRepresentation(XMLStreamWriter writer, + List valueRepresentations, + String dataType, + String origin) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(valueRepresentations)) { + for (ValueRepresentation valueRepresentation : valueRepresentations) { + if (valueRepresentation instanceof FacetValueTypeRepresentation) { + FacetValueTypeRepresentationImpl valueTypeRepresentation = (FacetValueTypeRepresentationImpl) valueRepresentation; + FacetValueType type = valueTypeRepresentation.getType(); + if (type != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + dataType); + XmlWriterUtils.writeCharacters(type.value(), writer); + writer.writeEndElement(); + } + } else if (valueRepresentation instanceof ListReferenceValueRepresentation) { + ListReferenceValueRepresentationImpl listReferenceValueRepresentation = (ListReferenceValueRepresentationImpl) valueRepresentation; + ArtefactReference reference = listReferenceValueRepresentation.getReference(); + if (reference != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + origin); + urnWriter.writeUrnCharacters(reference, writer); + writer.writeEndElement(); + } + } + } + } + } + + private void writeRepresentationMappings(XMLStreamWriter writer, List representationMappings) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(representationMappings)) { + for (RepresentationMapping representationMapping : representationMappings) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.REPRESENTATION_MAPPING); + + DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE.withZone(ZoneId.systemDefault()); + Instant validFrom = representationMapping.getValidFrom(); + if (validFrom != null) { + writer.writeAttribute(XmlConstants.VALID_FROM, formatter.format(validFrom)); + } + + Instant validTo = representationMapping.getValidTo(); + if (validTo != null) { + writer.writeAttribute(XmlConstants.VALID_TO, formatter.format(validTo)); + } + + this.annotableWriter.write(representationMapping, writer); + + List sourceValues = representationMapping.getSourceValues(); + List targetValues = representationMapping.getTargetValues(); + + writeSourceValues(writer, sourceValues); + writeTargetValues(writer, targetValues); + writer.writeEndElement(); + } + } + } + + private void writeTargetValues(XMLStreamWriter writer, List targetValues) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(targetValues)) { + for (TargetValue targetValue : targetValues) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.TARGET_VALUE); + XmlWriterUtils.writeCharacters(targetValue.getValue(), writer); + writer.writeEndElement(); + } + } + } + + private void writeSourceValues(XMLStreamWriter writer, List sourceValues) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(sourceValues)) { + for (MappedValue mappedValue : sourceValues) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.SOURCE_VALUE); + writer.writeAttribute(XmlConstants.IS_REG_EX, String.valueOf(mappedValue.isRegEx())); + writer.writeAttribute(XmlConstants.START_INDEX, String.valueOf(mappedValue.getStartIndex())); + writer.writeAttribute(XmlConstants.END_INDEX, String.valueOf(mappedValue.getEndIndex())); + String value = mappedValue.getValue(); + if (value != null) { + writer.writeCharacters(value); + } + writer.writeEndElement(); + } + } + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/RepresentationWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/RepresentationWriter.java new file mode 100644 index 0000000..3eb8aab --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/RepresentationWriter.java @@ -0,0 +1,209 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.writer.XmlWriterUtils.writeInternationalString; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Facet; +import com.epam.jsdmx.infomodel.sdmx30.FacetType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.infomodel.sdmx30.SentinelValue; +import com.epam.jsdmx.infomodel.sdmx30.TextFormatImpl; + +public class RepresentationWriter { + + private final UrnWriter urnWriter; + + public RepresentationWriter(UrnWriter urnWriter) { + this.urnWriter = urnWriter; + } + + private void writeEnumerated(XMLStreamWriter writer, Representation coreRepresentation) throws XMLStreamException { + ArtefactReference artefactReference = coreRepresentation.enumerated(); + if (artefactReference != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.ENUMERATION); + ArtefactReference maintainableArtefactReference = artefactReference.getMaintainableArtefactReference(); + if (maintainableArtefactReference != null) { + urnWriter.writeUrnCharacters(maintainableArtefactReference, writer); + } + writer.writeEndElement(); + + } + } + + public void writeRepresentation(XMLStreamWriter writer, Representation representation, String representationName) throws XMLStreamException { + if (representation != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + representationName); + boolean enumerated = representation.isEnumerated(); + if (enumerated) { + writeEnumerated(writer, representation); + } else { + writeTextFormat(writer, representation); + } + writer.writeEndElement(); + } + } + + private void writeTextFormat(XMLStreamWriter writer, Representation coreRepresentation) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.TEXT_FORMAT); + Set facets = coreRepresentation.nonEnumerated(); + if (!facets.isEmpty()) { + TextFormatImpl textFormat = new TextFormatImpl(facets); + writeTextFormatAttribute(writer, textFormat); + + writeSentinelValues(writer, textFormat); + } + writer.writeEndElement(); + } + + private void writeSentinelValues(XMLStreamWriter writer, TextFormatImpl textFormat) throws XMLStreamException { + if (textFormat.hasSentinelValues()) { + Optional> sentinelValues = textFormat.getSentinelValues(); + if (sentinelValues.isPresent()) { + List sentinelValueList = sentinelValues.get(); + for (SentinelValue sentinelValue : sentinelValueList) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.SENTINEL_VALUE); + String value = sentinelValue.getValue(); + if (value != null) { + writer.writeAttribute("value", value); + InternationalString name = sentinelValue.getName(); + writeInternationalString(name, writer, XmlConstants.COMMON + XmlConstants.COM_NAME); + InternationalString description = sentinelValue.getDescription(); + writeInternationalString(description, writer, XmlConstants.COMMON + XmlConstants.COM_DESCRIPTION); + } + writer.writeEndElement(); + } + } + } + } + + private void writeTextFormatAttribute(XMLStreamWriter writer, TextFormatImpl textFormat) throws XMLStreamException { + + if (textFormat.hasValueType()) { + Optional valueType = textFormat.getValueType(); + writer.writeAttribute(XmlConstants.TEXT_TYPE, valueType.get().value()); + } + + if (textFormat.hasDecimals()) { + Optional decimals = textFormat.getDecimals(); + if (decimals.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.DECIMALS.name()), String.valueOf(decimals.get())); + } + return; + } + + if (textFormat.hasEndTime()) { + Optional endTime = textFormat.getEndTime(); + if (endTime.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.END_TIME.name()), String.valueOf(endTime.get())); + } + return; + } + + if (textFormat.hasInterval()) { + Optional interval = textFormat.getInterval(); + if (interval.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.INTERVAL.name()), String.valueOf(interval.get())); + } + return; + } + + if (textFormat.hasEndValue()) { + Optional endValue = textFormat.getEndValue(); + if (endValue.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.END_VALUE.name()), String.valueOf(endValue.get())); + } + return; + } + + if (textFormat.hasIsMultiLingual()) { + Optional isMultiLingual = textFormat.getIsMultiLingual(); + if (isMultiLingual.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.IS_MULTILINGUAL.name()), String.valueOf(isMultiLingual.get())); + } + return; + } + + if (textFormat.hasIsSequence()) { + Optional isSequence = textFormat.getIsSequence(); + if (isSequence.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.IS_SEQUENCE.name()), String.valueOf(isSequence.get())); + } + return; + } + + if (textFormat.hasMaxValue()) { + Optional maxValue = textFormat.getMaxValue(); + if (maxValue.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.MAX_VALUE.name()), String.valueOf(maxValue.get())); + } + return; + } + + if (textFormat.hasMinValue()) { + Optional minValue = textFormat.getMinValue(); + if (minValue.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.MIN_VALUE.name()), String.valueOf(minValue.get())); + } + return; + } + + if (textFormat.hasMaxLength()) { + Optional maxLength = textFormat.getMaxLength(); + if (maxLength.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.MAX_LENGTH.name()), String.valueOf(maxLength.get())); + } + return; + } + + if (textFormat.hasMinLength()) { + Optional minLength = textFormat.getMinLength(); + if (minLength.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.MIN_LENGTH.name()), String.valueOf(minLength.get())); + } + return; + } + + if (textFormat.hasStartTime()) { + Optional startTime = textFormat.getStartTime(); + if (startTime.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.START_TIME.name()), String.valueOf(startTime.get())); + } + return; + } + + if (textFormat.hasStartValue()) { + Optional startValue = textFormat.getStartValue(); + if (startValue.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.START_VALUE.name()), String.valueOf(startValue.get())); + } + return; + } + + if (textFormat.hasPattern()) { + Optional pattern = textFormat.getPattern(); + if (pattern.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.PATTERN.name()), pattern.get()); + } + return; + } + + if (textFormat.hasTimeInterval()) { + Optional timeInterval = textFormat.getTimeInterval(); + if (timeInterval.isPresent()) { + writer.writeAttribute(XmlConstants.MAP_FACET_TYPE.get(FacetType.TIME_INTERVAL.name()), timeInterval.get()); + } + } + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/StructureMapWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/StructureMapWriter.java new file mode 100644 index 0000000..04d7b1e --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/StructureMapWriter.java @@ -0,0 +1,314 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ComponentMap; +import com.epam.jsdmx.infomodel.sdmx30.DateMap; +import com.epam.jsdmx.infomodel.sdmx30.DatePatternMap; +import com.epam.jsdmx.infomodel.sdmx30.EpochMap; +import com.epam.jsdmx.infomodel.sdmx30.EpochPeriodType; +import com.epam.jsdmx.infomodel.sdmx30.FixedValueMap; +import com.epam.jsdmx.infomodel.sdmx30.FrequencyFormatMapping; +import com.epam.jsdmx.infomodel.sdmx30.MappingRoleType; +import com.epam.jsdmx.infomodel.sdmx30.ResolvePeriod; +import com.epam.jsdmx.infomodel.sdmx30.StructureMap; +import com.epam.jsdmx.xml30.structure.reader.MappedComponent; +import com.epam.jsdmx.xml30.structure.reader.StructureMapUtils; + +import org.apache.commons.collections.CollectionUtils; + +public class StructureMapWriter extends XmlWriter { + + public StructureMapWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + } + + @Override + protected void writeAttributes(StructureMap structureMap, XMLStreamWriter writer) throws XMLStreamException { + this.commonAttributesWriter.writeAttributes(structureMap, writer); + } + + @Override + protected void writeCustomAttributeElements(StructureMap structureMap, XMLStreamWriter writer) throws XMLStreamException { + + ArtefactReference source = structureMap.getSource(); + writeArtefactReference(writer, source, XmlConstants.SOURCE); + + ArtefactReference target = structureMap.getTarget(); + writeArtefactReference(writer, target, XmlConstants.TARGET); + + List componentMaps = structureMap.getComponentMaps(); + + List epochMaps = structureMap.getEpochMaps(); + if (CollectionUtils.isNotEmpty(epochMaps)) { + Map> epochWithMappedComponent = StructureMapUtils.getEpochWithMappedComponent( + epochMaps, + componentMaps + ); + writeEpochMap(writer, epochWithMappedComponent); + } + + List datePatternMaps = structureMap.getDatePatternMaps(); + if (CollectionUtils.isNotEmpty(datePatternMaps)) { + Map> datePatternWithMappedComponent = StructureMapUtils.getDatePatternWithMappedComponent( + datePatternMaps, + componentMaps + ); + writeDatePatternMap(writer, datePatternWithMappedComponent); + } + + List frequencyFormatMappings = StructureMapUtils.getFrequencyFormatMappings(epochMaps, datePatternMaps); + if (CollectionUtils.isNotEmpty(frequencyFormatMappings)) { + writeFrequencyFormatMapping(writer, frequencyFormatMappings); + } + + List representationMap = StructureMapUtils.getRepresentationMap(structureMap); + if (CollectionUtils.isNotEmpty(representationMap)) { + writeComponentMap(writer, representationMap); + } + + List fixedComponentMaps = structureMap.getFixedComponentMaps(); + if (CollectionUtils.isNotEmpty(fixedComponentMaps)) { + writeFixedValueMap(writer, fixedComponentMaps); + } + + } + + @Override + protected String getName() { + return XmlConstants.STRUCTURE_MAP; + } + + @Override + protected String getNamePlural() { + return XmlConstants.STRUCTURE_MAPS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getStructureMaps(); + } + + private void writeComponentMap(XMLStreamWriter writer, List representationMap) throws XMLStreamException { + for (ComponentMap componentMap : representationMap) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.COMPONENT_MAP); + this.annotableWriter.write(componentMap, writer); + + for (String source : componentMap.getSource()) { + writeSource(writer, source); + } + + for (String target : componentMap.getTarget()) { + writeTarget(writer, target); + } + + ArtefactReference representationMapRef = componentMap.getRepresentationMap(); + if (representationMapRef != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.REPRESENTATION_MAP); + XmlWriterUtils.writeCharacters(representationMapRef.getUrn(), writer); + writer.writeEndElement(); + } + + writer.writeEndElement(); + } + } + + private void writeFixedValueMap(XMLStreamWriter writer, List fixedComponentMaps) throws XMLStreamException { + for (FixedValueMap fixedValueMap : fixedComponentMaps) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.FIXED_VALUE_MAP); + this.annotableWriter.write(fixedValueMap, writer); + writeComponent(writer, fixedValueMap); + String value = fixedValueMap.getValue(); + if (value != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.VALUE); + writer.writeCharacters(value); + writer.writeEndElement(); + } + + writer.writeEndElement(); + } + } + + private void writeComponent(XMLStreamWriter writer, FixedValueMap fixedValueMap) throws XMLStreamException { + String component = fixedValueMap.getComponent(); + if (component != null) { + MappingRoleType role = fixedValueMap.getRole(); + if (MappingRoleType.SOURCE.equals(role)) { + writeSource(writer, component); + } else { + writeTarget(writer, component); + } + } + } + + private void writeFrequencyFormatMapping(XMLStreamWriter writer, List frequencyFormatMappings) throws XMLStreamException { + for (FrequencyFormatMapping frequencyFormatMapping : frequencyFormatMappings) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.FREQUENCY_FORMAT_MAPPING); + XmlWriterUtils.writeIdUriAttributes(writer, frequencyFormatMapping.getId(), frequencyFormatMapping.getUri()); + if (frequencyFormatMapping.getContainer() != null) { + writer.writeAttribute(XmlConstants.URN, frequencyFormatMapping.getUrn()); + } + this.annotableWriter.write(frequencyFormatMapping, writer); + String frequencyCode = frequencyFormatMapping.getFrequencyCode(); + if (frequencyCode != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.FREQUENCY_ID); + writer.writeCharacters(frequencyCode); + writer.writeEndElement(); + } + + String datePattern = frequencyFormatMapping.getDatePattern(); + if (datePattern != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.DATE_PATTERN); + writer.writeCharacters(datePattern); + writer.writeEndElement(); + } + writer.writeEndElement(); + } + } + + private void writeDatePatternMap(XMLStreamWriter writer, Map> datePatternMaps) throws XMLStreamException { + for (Map.Entry> datePatternMap : datePatternMaps.entrySet()) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.DATE_PATTERN_MAP); + + writeDatePatternMapAttributes(writer, datePatternMap.getKey()); + writeDateMapElements(writer, datePatternMap.getKey(), datePatternMap.getValue()); + + writer.writeEndElement(); + } + } + + private void writeEpochMap(XMLStreamWriter writer, Map> epochMaps) throws XMLStreamException { + for (Map.Entry> epochMap : epochMaps.entrySet()) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.EPOCH_MAP); + + writeEpochMapAttributes(writer, epochMap.getKey()); + writeDateMapElements(writer, epochMap.getKey(), epochMap.getValue()); + + writer.writeEndElement(); + } + } + + private void writeDateMapElements(XMLStreamWriter writer, DateMap dateMap, List mappedComponents) throws XMLStreamException { + this.annotableWriter.write(dateMap, writer); + writeSourceTarget(writer, mappedComponents); + + String frequencyDimension = dateMap.getFrequencyDimension(); + writeFrequency(writer, frequencyDimension, XmlConstants.FREQUENCY_DIMENSION); + + List mappedFrequencies = dateMap.getMappedFrequencies(); + writeMappedFrequencies(writer, mappedFrequencies); + + String targetFrequencyId = dateMap.getTargetFrequencyId(); + writeFrequency(writer, targetFrequencyId, XmlConstants.TARGET_FREQUENCY_ID); + } + + private void writeSourceTarget(XMLStreamWriter writer, List mappedComponents) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(mappedComponents)) { + for (MappedComponent mappedComponent : mappedComponents) { + String source = mappedComponent.getSource(); + writeSource(writer, source); + + String target = mappedComponent.getTarget(); + writeTarget(writer, target); + } + } + } + + private void writeTarget(XMLStreamWriter writer, String target) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.TARGET); + XmlWriterUtils.writeCharacters(target, writer); + writer.writeEndElement(); + } + + private void writeSource(XMLStreamWriter writer, String source) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.SOURCE); + XmlWriterUtils.writeCharacters(source, writer); + writer.writeEndElement(); + } + + private void writeMappedFrequencies(XMLStreamWriter writer, List mappedFrequencies) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(mappedFrequencies)) { + for (FrequencyFormatMapping mapping : mappedFrequencies) { + if (mapping != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.MAPPED_FREQUENCIES); + XmlWriterUtils.writeCharacters(mapping.getId(), writer); + writer.writeEndElement(); + } + } + } + } + + private void writeFrequency(XMLStreamWriter writer, String frequency, String frequencyName) throws XMLStreamException { + if (frequency != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + frequencyName); + writer.writeCharacters(frequency); + writer.writeEndElement(); + } + } + + private void writeEpochMapAttributes(XMLStreamWriter writer, EpochMap epochMap) throws XMLStreamException { + writeCommonDateMapAttributes( + writer, + epochMap + ); + + Instant basePeriod = epochMap.getBasePeriod(); + if (basePeriod != null) { + writer.writeAttribute(XmlConstants.BASE_PERIOD, basePeriod.toString()); + } + + EpochPeriodType epochPeriod = epochMap.getEpochPeriod(); + if (epochPeriod != null) { + writer.writeAttribute(XmlConstants.EPOCH_PERIOD, XmlConstants.EPOCH_PERIOD_STRING_MAP.get(epochPeriod)); + } + } + + private void writeDatePatternMapAttributes(XMLStreamWriter writer, DatePatternMap datePatternMap) throws XMLStreamException { + writeCommonDateMapAttributes(writer, datePatternMap); + + String sourcePattern = datePatternMap.getSourcePattern(); + if (sourcePattern != null) { + writer.writeAttribute(XmlConstants.SOURCE_PATTERN, sourcePattern); + } + + String locale = datePatternMap.getLocale(); + if (locale != null) { + writer.writeAttribute(XmlConstants.LOCALE, locale); + } + } + + private void writeCommonDateMapAttributes(XMLStreamWriter writer, + DateMap dateMap) throws XMLStreamException { + XmlWriterUtils.writeIdUriAttributes(writer, dateMap.getId(), dateMap.getUri()); + + if (dateMap.getContainer() != null) { + writer.writeAttribute(XmlConstants.URN, dateMap.getUrn()); + } + + ResolvePeriod resolvePeriod = dateMap.getResolvePeriod(); + if (resolvePeriod != null) { + writer.writeAttribute(XmlConstants.RESOLVE_PERIOD, XmlConstants.RESOLVE_PERIOD_STRING_MAP.get(resolvePeriod)); + } + } + + private void writeArtefactReference(XMLStreamWriter writer, + ArtefactReference source, + String artefactReferenceName) throws XMLStreamException { + if (source != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + artefactReferenceName); + XmlWriterUtils.writeCharacters(source.getUrn(), writer); + writer.writeEndElement(); + } + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/UrnWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/UrnWriter.java new file mode 100644 index 0000000..d2fafc6 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/UrnWriter.java @@ -0,0 +1,44 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +public class UrnWriter { + + private final ReferenceAdapter referenceAdapter; + + public UrnWriter(ReferenceAdapter referenceAdapter) { + this.referenceAdapter = referenceAdapter; + } + + public void writeUrnCharacters(ArtefactReference ref, XMLStreamWriter writer) throws XMLStreamException { + if (ref != null) { + String urn = referenceAdapter.toAdaptedUrn(ref); + XmlWriterUtils.writeCharacters(urn, writer); + } + } + + public void writeUrnCharacters(String ref, XMLStreamWriter writer) throws XMLStreamException { + if (ref != null) { + String urn = referenceAdapter.adaptUrn(ref); + XmlWriterUtils.writeCharacters(urn, writer); + } + } + + public void writeUrn(String urn, XMLStreamWriter writer) throws XMLStreamException { + if (urn != null) { + XmlWriterUtils.writeUrn(referenceAdapter.adaptUrn(urn), writer); + } + } + + public String adaptUrn(String urn) { + return referenceAdapter.adaptUrn(urn); + } + + public String adaptType(String type) { + return referenceAdapter.adaptType(type); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ValueListWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ValueListWriter.java new file mode 100644 index 0000000..2eafc05 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/ValueListWriter.java @@ -0,0 +1,65 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.writer.XmlWriterUtils.writeInternationalString; + +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.ValueItem; +import com.epam.jsdmx.infomodel.sdmx30.ValueList; + +import org.apache.commons.collections.CollectionUtils; + +public class ValueListWriter extends XmlWriter { + + public ValueListWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter) { + super(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter); + } + + @Override + protected void writeAttributes(ValueList artefact, XMLStreamWriter writer) throws XMLStreamException { + commonAttributesWriter.writeAttributes(artefact, writer); + } + + @Override + protected void writeCustomAttributeElements(ValueList valueList, XMLStreamWriter writer) throws XMLStreamException { + List items = valueList.getItems(); + if (CollectionUtils.isNotEmpty(items)) { + for (ValueItem valueItem : items) { + if (valueItem != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.VALUE_ITEM); + writer.writeAttribute(XmlConstants.ID, valueItem.getId()); + annotableWriter.write(valueItem, writer); + InternationalString name = valueItem.getName(); + writeInternationalString(name, writer, XmlConstants.COMMON + XmlConstants.COM_NAME); + InternationalString description = valueItem.getDescription(); + writeInternationalString(description, writer, XmlConstants.COMMON + XmlConstants.COM_DESCRIPTION); + writer.writeEndElement(); + } + } + } + } + + @Override + protected String getName() { + return XmlConstants.VALUE_LIST; + } + + @Override + protected String getNamePlural() { + return XmlConstants.VALUE_LISTS; + } + + @Override + protected Set extractArtefacts(Artefacts artefacts) { + return artefacts.getValueLists(); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlConstants.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlConstants.java new file mode 100644 index 0000000..0081416 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlConstants.java @@ -0,0 +1,377 @@ +package com.epam.jsdmx.xml30.structure.writer; + + +import com.epam.jsdmx.infomodel.sdmx30.CascadeValue; +import com.epam.jsdmx.infomodel.sdmx30.ConstraintRoleType; +import com.epam.jsdmx.infomodel.sdmx30.EpochPeriodType; +import com.epam.jsdmx.infomodel.sdmx30.FacetType; +import com.epam.jsdmx.infomodel.sdmx30.ResolvePeriod; + +import org.apache.commons.collections4.BidiMap; +import org.apache.commons.collections4.bidimap.DualHashBidiMap; + +public final class XmlConstants { + + public static final String SCHEMAS_V_3_0_MESSAGE = "http://www.sdmx.org/resources/sdmxml/schemas/v3_0/message"; + public static final String SCHEMAS_V_3_0_STRUCTURE = "http://www.sdmx.org/resources/sdmxml/schemas/v3_0/structure"; + public static final String SCHEMAS_V_3_0_COMMON = "http://www.sdmx.org/resources/sdmxml/schemas/v3_0/common"; + public static final String XMLSCHEMA_INSTANCE = "http://www.w3.org/2001/XMLSchema-instance"; + public static final String XML_1998_NAMESPACE = "http://www.w3.org/XML/1998/namespace"; + public static final String SS_NAMESPACE = "http://www.sdmx.org/resources/sdmxml/schemas/v3_0/data/structurespecific"; + + public static final String COMMON = "common:"; + public static final String STRUCTURE = "structure:"; + public static final String MESSAGE = "message:"; + + public static final String PREFIX = "prefix"; + public static final String HEADER = "Header"; + public static final String MES_ID = "ID"; + public static final String MES_TEST = "Test"; + public static final String PREPARED = "Prepared"; + public static final String SENDER = "Sender"; + public static final String RECEIVER = "Receiver"; + + public static final String MES_STRUCTURES = "Structures"; + public static final String HIERARCHIES = "Hierarchies"; + public static final String CODELISTS = "Codelists"; + public static final String CONCEPT_SCHEMES = "ConceptSchemes"; + public static final String DATA_STRUCTURES = "DataStructures"; + public static final String DATAFLOWS = "Dataflows"; + public static final String METADATA_STRUCTURES = "MetadataStructures"; + public static final String METADATA_FLOWS = "Metadataflows"; + public static final String REPRESENTATION_MAPS = "RepresentationMaps"; + public static final String STRUCTURE_MAPS = "StructureMaps"; + public static final String CATEGORISATIONS = "Categorisations"; + public static final String CATEGORY_SCHEMES = "CategorySchemes"; + public static final String AGENCY_SCHEMES = "AgencySchemes"; + public static final String CATEGORY_SCHEME_MAPS = "CategorySchemeMaps"; + public static final String CONCEPT_SCHEME_MAPS = "ConceptSchemeMaps"; + public static final String DATA_CONSTRAINTS = "DataConstraints"; + public static final String DATA_CONSUMER_SCHEMES = "DataConsumerSchemes"; + public static final String DATA_PROVIDER_SCHEMES = "DataProviderSchemes"; + public static final String METADATA_PROVIDER_SCHEMES = "MetadataProviderSchemes"; + public static final String HIERARCHY_ASSOCIATIONS = "HierarchyAssociations"; + public static final String METADATA_CONSTRAINTS = "MetadataConstraints"; + public static final String METADATA_PROVISION_AGREEMENTS = "MetadataProvisionAgreements"; + public static final String ORGANISATION_SCHEME_MAPS = "OrganisationSchemeMaps"; + public static final String PROCESSES = "Processes"; + public static final String PROVISION_AGREEMENTS = "ProvisionAgreements"; + public static final String REPORTING_TAXONOMIES = "ReportingTaxonomies"; + public static final String REPORTING_TAXONOMY_MAPS = "ReportingTaxonomyMaps"; + public static final String VALUE_LISTS = "ValueLists"; + public static final String GEO_CODELISTS = "GeographicCodelists"; + public static final String GEOGRID_CODELISTS = "GeoGridCodelists"; + + public static final String MES_STRUCTURE = "Structure"; + public static final String CODELIST = "Codelist"; + public static final String HIERARCHY = "Hierarchy"; + public static final String CONCEPT_SCHEME = "ConceptScheme"; + public static final String DATA_STRUCTURE = "DataStructure"; + public static final String DATAFLOW = "Dataflow"; + public static final String METADATA_FLOW = "Metadataflow"; + public static final String REPRESENTATION_MAP = "RepresentationMap"; + public static final String STRUCTURE_MAP = "StructureMap"; + public static final String CATEGORISATION = "Categorisation"; + public static final String CATEGORY_SCHEME = "CategoryScheme"; + public static final String AGENCY_SCHEME = "AgencyScheme"; + public static final String CATEGORY_SCHEME_MAP = "CategorySchemeMap"; + public static final String CONCEPT_SCHEME_MAP = "ConceptSchemeMap"; + public static final String DATA_CONSTRAINT = "DataConstraint"; + public static final String DATA_CONSUMER_SCHEME = "DataConsumerScheme"; + public static final String DATA_PROVIDER_SCHEME = "DataProviderScheme"; + public static final String METADATA_PROVIDER_SCHEME = "MetadataProviderScheme"; + public static final String HIERARCHY_ASSOCIATION = "HierarchyAssociation"; + public static final String METADATA_CONSTRAINT = "MetadataConstraint"; + public static final String ORGANISATION_SCHEME_MAP = "OrganisationSchemeMap"; + public static final String PROCESS = "Process"; + public static final String PROVISION_AGREEMENT = "ProvisionAgreement"; + public static final String REPORTING_TAXONOMY = "ReportingTaxonomy"; + public static final String REPORTING_TAXONOMY_MAP = "ReportingTaxonomyMap"; + public static final String VALUE_LIST = "ValueList"; + public static final String GEO_CODELIST = "GeographicCodelist"; + public static final String GEOGRID_CODELIST = "GeoGridCodelist"; + + public static final String INCLUSIVE_CODE_SELECTION = "InclusiveCodeSelection"; + public static final String EXCLUSIVE_CODE_SELECTION = "ExclusiveCodeSelection"; + public static final String MEMBER_VALUE = "MemberValue"; + public static final String CODELIST_EXTENSION = "CodelistExtension"; + public static final String CASCADE_VALUES = "cascadeValues"; + + public static final String COM_ANNOTATIONS = "Annotations"; + public static final String COM_ANNOTATION = "Annotation"; + public static final String COM_ANNOTATION_TITLE = "AnnotationTitle"; + public static final String COM_ANNOTATION_TYPE = "AnnotationType"; + public static final String COM_ANNOTATION_URL = "AnnotationURL"; + public static final String COM_ANNOTATION_TEXT = "AnnotationText"; + public static final String COM_ANNOTATION_VALUE = "AnnotationValue"; + + public static final String COM_NAME = "Name"; + public static final String COM_DESCRIPTION = "Description"; + public static final String COM_LINK = "Link"; + public static final String STR_CODE = "Code"; + public static final String STRUCTURE_PARENT = "Parent"; + + public static final String CANNOT_BE_NULL = " cannot be null!"; + public static final String STRUCTURE_URL = "structureUrl"; + public static final String SERVICE_URL = "serviceUrl"; + + public static final String HAS_FORMAL_LEVELS = "hasFormalLevels"; + public static final String DOES_NOT_SUPPORT_ELEMENT = "does not support element: "; + + + public static final String CODE = "Code"; + public static final String LEVEL = "Level"; + public static final String CODING_FORMAT = "CodingFormat"; + public static final String HIERARCHICAL_CODE = "HierarchicalCode"; + + public static final String CONCEPT = "Concept"; + + public static final String CORE_REPRESENTATION = "CoreRepresentation"; + public static final String PARENT = "Parent"; + public static final String ENUMERATION = "Enumeration"; + public static final String ENUMERATION_FORMAT = "EnumerationFormat"; + public static final String TEXT_FORMAT = "TextFormat"; + public static final String TEXT = "Text"; + public static final String SENTINEL_VALUE = "SentinelValue"; + public static final String ISOCONCEPT_REFERENCE = "ISOConceptReference"; + public static final String CONCEPT_AGENCY = "ConceptAgency"; + public static final String CONCEPT_SCHEME_ID = "ConceptSchemeID"; + public static final String CONCEPT_ID = "ConceptID"; + + public static final String DATA_STRUCTURE_COMPONENTS = "DataStructureComponents"; + public static final String METADATA = "Metadata"; + + + public static final String ATTRIBUTE_LIST = "AttributeList"; + public static final String METADATA_ATTRIBUTE_USAGE = "MetadataAttributeUsage"; + public static final String METADATA_ATTRIBUTE_REFERENCE = "MetadataAttributeReference"; + public static final String ATTRIBUTE = "Attribute"; + public static final String USAGE = "usage"; + public static final String MANDATORY = "mandatory"; + public static final String OPTIONAL = "optional"; + public static final String MEASURE_RELATIONSHIP = "MeasureRelationship"; + public static final String MEASURE = "Measure"; + public static final String DIMENSION = "Dimension"; + public static final String OBSERVATION = "Observation"; + public static final String GROUP = "Group"; + public static final String MEASURE_LIST = "MeasureList"; + public static final String LOCAL_REPRESENTATION = "LocalRepresentation"; + + public static final String DIMENSION_LIST = "DimensionList"; + public static final String GROUP_DIMENSION = "GroupDimension"; + public static final String DIMENSION_REFERENCE = "DimensionReference"; + public static final String TIME_DIMENSION = "TimeDimension"; + public static final String POSITION = "position"; + public static final String ATTRIBUTE_RELATIONSHIP = "AttributeRelationship"; + public static final BidiMap MAP_FACET_TYPE = new DualHashBidiMap<>(); + public static final String CONCEPT_IDENTITY = "ConceptIdentity"; + public static final String CONCEPT_ROLE = "ConceptRole"; + public static final String LANG = "lang"; + public static final String STRUCTURE_UPPER = "Structure"; + public static final String MIN_OCCURS = "minOccurs"; + public static final String MAX_OCCURS = "maxOccurs"; + public static final String IS_PRESENTATIONAL = "isPresentational"; + public static final String METADATA_ATTRIBUTE = "MetadataAttribute"; + public static final String METADATA_ATTRIBUTE_LIST = "MetadataAttributeList"; + public static final String METADATA_STRUCTURE_COMPONENTS = "MetadataStructureComponents"; + + public static final String TARGET = "Target"; + public static final String SOURCE_DATA_TYPE = "SourceDataType"; + public static final String TARGET_DATA_TYPE = "TargetDataType"; + public static final String SOURCE_CODELIST = "SourceCodelist"; + public static final String TARGET_CODELIST = "TargetCodelist"; + public static final String REPRESENTATION_MAPPING = "RepresentationMapping"; + public static final String TARGET_VALUE = "TargetValue"; + public static final String SOURCE_VALUE = "SourceValue"; + + public static final String MEASURE_DESCRIPTOR_ID = "MeasureDescriptor"; + public static final String ATTRIBUTE_DESCRIPTOR_ID = "AttributeDescriptor"; + public static final String METADATA_ATTRIBUTE_DESCRIPTOR_ID = "MetadataAttributeDescriptor"; + public static final String DIMENSION_DESCRIPTOR_ID = "DimensionDescriptor"; + + public static final String SOURCE = "Source"; + public static final String COMPONENT_MAP = "ComponentMap"; + public static final String FIXED_VALUE_MAP = "FixedValueMap"; + public static final String VALUE = "Value"; + public static final String FREQUENCY_ID = "FrequencyId"; + public static final String DATE_PATTERN = "DatePattern"; + public static final String FREQUENCY_FORMAT_MAPPING = "FrequencyFormatMapping"; + public static final String DATE_PATTERN_MAP = "DatePatternMap"; + public static final String EPOCH_MAP = "EpochMap"; + public static final String FREQUENCY_DIMENSION = "FrequencyDimension"; + public static final String TARGET_FREQUENCY_ID = "TargetFrequencyID"; + public static final String MAPPED_FREQUENCIES = "MappedFrequencies"; + public static final String CATEGORY = "Category"; + + public static final BidiMap STRING_RESOLVE_PERIOD_MAP = new DualHashBidiMap<>(); + public static final BidiMap RESOLVE_PERIOD_STRING_MAP = STRING_RESOLVE_PERIOD_MAP.inverseBidiMap(); + + public static final BidiMap STRING_EPOCH_PERIOD_MAP = new DualHashBidiMap<>(); + public static final BidiMap EPOCH_PERIOD_STRING_MAP = STRING_EPOCH_PERIOD_MAP.inverseBidiMap(); + + public static final BidiMap CASCADE_VALUE_TYPE_STRING = new DualHashBidiMap<>(); + public static final BidiMap STRING_CASCADE_VALUE_TYPE = CASCADE_VALUE_TYPE_STRING.inverseBidiMap(); + + public static final BidiMap CONSTRAINT_ROLE_STRING = new DualHashBidiMap<>(); + public static final BidiMap STRING_CONSTRAINT_ROLE = CONSTRAINT_ROLE_STRING.inverseBidiMap(); + public static final String XML_LANG = "xml:lang"; + + public static final String CONTACT = "Contact"; + public static final String NAME = "Name"; + public static final String DEPARTMENT = "Department"; + public static final String ROLE = "Role"; + public static final String TELEPHONE = "Telephone"; + public static final String FAX = "Fax"; + public static final String X_400 = "X400"; + public static final String EMAIL = "Email"; + public static final String AGENCY = "Agency"; + public static final String URI = "URI"; + public static final String ITEM_MAP = "ItemMap"; + + public static final String DATA_CONSUMER = "DataConsumer"; + public static final String DATA_CONSUMERS = "DATA_CONSUMERS"; + public static final String DATA_PROVIDER = "DataProvider"; + public static final String DATA_PROVIDERS = "DATA_PROVIDERS"; + public static final String METADATA_PROVIDERS = "METADATA_PROVIDERS"; + public static final String ORGANISATION_UNIT_SCHEMES = "OrganisationUnitSchemes"; + + public static final String LINKED_HIERARCHY = "LinkedHierarchy"; + public static final String LINKED_OBJECT = "LinkedObject"; + public static final String CONTEXT_OBJECT = "ContextObject"; + public static final String ROLE_ATTR = "role"; + public static final String CONSTRAINT_ATTACHMENT = "ConstraintAttachment"; + public static final String RELEASE_CALENDAR = "ReleaseCalendar"; + public static final String METADATA_TARGET_REGION = "MetadataTargetRegion"; + public static final String OFFSET = "Offset"; + public static final String PERIODICITY = "Periodicity"; + public static final String TOLERANCE = "Tolerance"; + public static final String IS_INCLUSIVE = "isInclusive"; + public static final String START_PERIOD = "StartPeriod"; + public static final String END_PERIOD = "EndPeriod"; + public static final String BEFORE_PERIOD = "BeforePeriod"; + public static final String AFTER_PERIOD = "AfterPeriod"; + public static final String TIME_RANGE = "TimeRange"; + public static final String INCLUDE = "include"; + public static final String COMPONENT = "Component"; + public static final String KEY_VALUE = "KeyValue"; + public static final String REMOVE_PREFIX = "removePrefix"; + public static final String ALLOWED = "Allowed"; + public static final String METADATA_PROVIDER = "MetadataProvider"; + public static final String METADATA_SET = "MetadataSet"; + public static final String METADATA_STRUCTURE = "MetadataStructure"; + public static final String METADATAFLOW = "Metadataflow"; + public static final String METADATA_PROVISION_AGREEMENT = "MetadataProvisionAgreement"; + public static final String ORGANISATION_UNIT_SCHEME = "OrganisationUnitScheme"; + public static final String ORGANISATION_UNIT = "OrganisationUnit"; + public static final String LOCAL_ID = "localID"; + public static final String TARGET_STEP = "TargetStep"; + public static final String CONDITION = "Condition"; + public static final String INPUT = "Input"; + public static final String OUTPUT = "Output"; + public static final String SOFTWARE_LANGUAGE = "softwareLanguage"; + public static final String SOFTWARE_VERSION = "softwareVersion"; + public static final String SOFTWARE_PACKAGE = "softwarePackage"; + public static final String DESCRIPTION = "Description"; + public static final String OBJECT_REFERENCE = "ObjectReference"; + public static final String COMPUTATION = "Computation"; + public static final String TRANSITION = "Transition"; + public static final String PROCESS_STEP = "ProcessStep"; + public static final String VALUE_ITEM = "ValueItem"; + + public static final String REPORTING_CATEGORY = "ReportingCategory"; + public static final String PROVISIONING_METADATA = "ProvisioningMetadata"; + public static final String STRUCTURAL_METADATA = "StructuralMetadata"; + public static final String IS_INCLUDED = "isIncluded"; + public static final String KEY = "Key"; + public static final String CUBE_REGION = "CubeRegion"; + public static final String DATA_KEY_SET = "DataKeySet"; + public static final String TEXT_TYPE = "textType"; + public static final String ID = "id"; + public static final String NAME_LOWER = "name"; + public static final String NAMES = "names"; + public static final String VERSION = "version"; + public static final String AGENCY_ID = "agencyID"; + public static final String DESCRIPTION_LOWER = "description"; + public static final String DESCRIPTIONS = "descriptions"; + public static final String VALID_TO = "validTo"; + public static final String VALID_FROM = "validFrom"; + public static final String YEAR_PATTERN = "yyyy"; + public static final String IS_PARTIAL = "isPartial"; + public static final String IS_REG_EX = "isRegEx"; + public static final String START_INDEX = "startIndex"; + public static final String END_INDEX = "endIndex"; + public static final String LOCALE = "locale"; + public static final String SOURCE_PATTERN = "sourcePattern"; + public static final String RESOLVE_PERIOD = "resolvePeriod"; + public static final String IS_EXTERNAL_REFERENCE = "isExternalReference"; + public static final String BASE_PERIOD = "basePeriod"; + public static final String EPOCH_PERIOD = "epochPeriod"; + public static final String URN = "urn"; + public static final String TYPE = "type"; + public static final String REL = "rel"; + public static final String URL = "url"; + public static final String DEFAULT_VERSION = "1.0"; + + public static final String GEOGRAPHIC_CODELISTS = "geographicCodelists"; + public static final String GEO_TYPE = "geoType"; + public static final String GEOGRAPHIC_CODELIST = "GeographicCodelist"; + public static final String GEO_FEATURE_SET_CODE = "GeoFeatureSetCode"; + public static final String VALUE_LOWER = "value"; + + public static final String GEOGRID_CODELIST_TYPE = "GeoGridCodelist"; + public static final String GRID_DEFINITION = "GridDefinition"; + public static final String GEO_GRID_CODES = "GeoGridCode"; + public static final String GEO_CELL = "GeoCell"; + public static final BidiMap MAP_CODING_FORMAT = MAP_FACET_TYPE.inverseBidiMap(); + + public static final String STRUCTURE_ELEMENT = "Structure"; + public static final String STRUCTURE_ID = "structureID"; + public static final String NAMESPACE = "namespace"; + public static final String DIMENSION_AT_OBSERVATION = "dimensionAtObservation"; + + static { + STRING_RESOLVE_PERIOD_MAP.put("startOfPeriod", ResolvePeriod.START_OF_PERIOD); + STRING_RESOLVE_PERIOD_MAP.put("endOfPeriod", ResolvePeriod.END_OF_PERIOD); + STRING_RESOLVE_PERIOD_MAP.put("midPeriod", ResolvePeriod.MID_PERIOD); + } + + static { + CASCADE_VALUE_TYPE_STRING.put(CascadeValue.TRUE, "true"); + CASCADE_VALUE_TYPE_STRING.put(CascadeValue.FALSE, "false"); + CASCADE_VALUE_TYPE_STRING.put(CascadeValue.EXCLUDE_ROOT, "excluderoot"); + } + + static { + CONSTRAINT_ROLE_STRING.put(ConstraintRoleType.ALLOWABLE_CONTENT, ALLOWED); + CONSTRAINT_ROLE_STRING.put(ConstraintRoleType.ACTUAL_CONTENT, "Actual"); + } + + static { + STRING_EPOCH_PERIOD_MAP.put("day", EpochPeriodType.DAY); + STRING_EPOCH_PERIOD_MAP.put("second", EpochPeriodType.SECOND); + STRING_EPOCH_PERIOD_MAP.put("microsecond", EpochPeriodType.MICROSECOND); + STRING_EPOCH_PERIOD_MAP.put("millisecond", EpochPeriodType.MILLISECOND); + STRING_EPOCH_PERIOD_MAP.put("nanosecond", EpochPeriodType.NANOSECOND); + } + + static { + MAP_FACET_TYPE.put(FacetType.INTERVAL.name(), "interval"); + MAP_FACET_TYPE.put(FacetType.DECIMALS.name(), "decimals"); + MAP_FACET_TYPE.put(FacetType.IS_MULTILINGUAL.name(), "isMultiLingual"); + MAP_FACET_TYPE.put(FacetType.END_VALUE.name(), "endValue"); + MAP_FACET_TYPE.put(FacetType.END_TIME.name(), "endTime"); + MAP_FACET_TYPE.put(FacetType.IS_SEQUENCE.name(), "isSequence"); + MAP_FACET_TYPE.put(FacetType.MAX_LENGTH.name(), "maxLength"); + MAP_FACET_TYPE.put(FacetType.MAX_VALUE.name(), "maxValue"); + MAP_FACET_TYPE.put(FacetType.MIN_LENGTH.name(), "minLength"); + MAP_FACET_TYPE.put(FacetType.MIN_VALUE.name(), "minValue"); + MAP_FACET_TYPE.put(FacetType.PATTERN.name(), "pattern"); + MAP_FACET_TYPE.put(FacetType.SENTINEL_VALUES.name(), "sentinelValues"); + MAP_FACET_TYPE.put(FacetType.START_TIME.name(), "startTime"); + MAP_FACET_TYPE.put(FacetType.START_VALUE.name(), "startValue"); + MAP_FACET_TYPE.put(FacetType.TIME_INTERVAL.name(), "timeInterval"); + } + + private XmlConstants() { + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlStructureWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlStructureWriter.java new file mode 100644 index 0000000..df75f5b --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlStructureWriter.java @@ -0,0 +1,89 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.serializer.sdmx30.structure.StructureWriter; + +import com.sun.xml.txw2.output.IndentingXMLStreamWriter; +import lombok.SneakyThrows; + +/** + * Streaming serialization for xml (3.0) + */ +public class XmlStructureWriter implements StructureWriter { + protected final HeaderWriter headerWriter; + private final XMLStreamWriter writer; + private final List> writerList; + + @SneakyThrows + public XmlStructureWriter(OutputStream outputStream, + List> writerList, + HeaderWriter headerWriter, + boolean isPretty) { + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); + this.writer = isPretty ? new IndentingXMLStreamWriter(xmlStreamWriter) : xmlStreamWriter; + this.writerList = List.copyOf(writerList); + this.headerWriter = headerWriter; + } + + @Override + @SneakyThrows + public void write(Artefacts artefacts) { + try { + writer.writeStartDocument(); + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.MES_STRUCTURE); + writeNameSpaces(); + writer.writeAttribute("xsi:schemaLocation", "http://www.sdmx.org/resources/sdmxml/schemas/v3_0/message ../../schemas/SDMXMessage.xsd"); + + headerWriter.writeDefaultHeader(writer); + + writer.writeStartElement(XmlConstants.MESSAGE + XmlConstants.MES_STRUCTURES); + + writerList.forEach(xmlWriter -> { + try { + Set maintainableArtefacts = xmlWriter.extractArtefacts(artefacts); + if (!maintainableArtefacts.isEmpty()) { + writer.writeStartElement(XmlConstants.STRUCTURE + xmlWriter.getNamePlural()); + maintainableArtefacts.forEach(artefact -> { + try { + xmlWriter.write(artefact, writer); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + }); + writer.writeEndElement(); + } + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + }); + + writer.writeEndElement(); + + writer.writeEndElement(); + writer.writeEndDocument(); + writer.close(); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + + private void writeNameSpaces() throws XMLStreamException { + writer.writeNamespace("message", XmlConstants.SCHEMAS_V_3_0_MESSAGE); + writer.writeNamespace("structure", XmlConstants.SCHEMAS_V_3_0_STRUCTURE); + writer.writeNamespace("common", XmlConstants.SCHEMAS_V_3_0_COMMON); + writer.writeNamespace("xsi", XmlConstants.XMLSCHEMA_INSTANCE); + writer.writeNamespace("xml", XmlConstants.XML_1998_NAMESPACE); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlWriter.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlWriter.java new file mode 100644 index 0000000..3f9dd79 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlWriter.java @@ -0,0 +1,66 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.util.Optional; +import java.util.Set; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; + +public abstract class XmlWriter { + + protected NameableWriter nameableWriter; + protected AnnotableWriter annotableWriter; + protected CommonAttributesWriter commonAttributesWriter; + protected LinksWriter linksWriter; + + + protected XmlWriter(NameableWriter nameableWriter, + AnnotableWriter annotableWriter, + CommonAttributesWriter commonAttributesWriter, + LinksWriter linksWriter) { + this.nameableWriter = nameableWriter; + this.annotableWriter = annotableWriter; + this.commonAttributesWriter = commonAttributesWriter; + this.linksWriter = linksWriter; + } + + protected abstract void writeAttributes(T artefact, XMLStreamWriter writer) throws XMLStreamException; + + protected abstract void writeCustomAttributeElements(T artefact, XMLStreamWriter writer) throws XMLStreamException; + + protected abstract String getName(); + + protected abstract String getNamePlural(); + + + protected void writeCommon(T artefact, XMLStreamWriter writer) throws XMLStreamException { + annotableWriter.write(artefact, writer); + linksWriter.write(artefact.getLinks(), writer); + nameableWriter.write(artefact, writer); + } + + protected abstract Set extractArtefacts(Artefacts artefacts); + + public void write(MaintainableArtefact maintainableArtefact, XMLStreamWriter writer) throws XMLStreamException { + T artefact = (T) maintainableArtefact; + writer.writeStartElement(XmlConstants.STRUCTURE + getName()); + writeAttributes(artefact, writer); + writeCommon(artefact, writer); + writeCustomAttributeElements(artefact, writer); + writer.writeEndElement(); + cleanData(); + } + + public Optional getWritableArtefactStructureClass() { + // if there is a need to find writer by its maintainable artefact type + return Optional.empty(); + } + + private void cleanData() { + //individual for each artefact + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlWriterFactory.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlWriterFactory.java new file mode 100644 index 0000000..4d35305 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlWriterFactory.java @@ -0,0 +1,131 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefact; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; +import com.epam.jsdmx.serializer.common.StubDataStructureLocalRepresentationAdapter; +import com.epam.jsdmx.serializer.common.TimeDimensionLocalRepresentationAdapter; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultHeaderProvider; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultReferenceAdapter; + +public class XmlWriterFactory { + + private final boolean isPretty; + private final ReferenceAdapter referenceAdapter; + private final TimeDimensionLocalRepresentationAdapter timeDimensionLocalRepresentationAdapter; + + public XmlWriterFactory(boolean isPretty) { + this.isPretty = isPretty; + referenceAdapter = new DefaultReferenceAdapter(); + timeDimensionLocalRepresentationAdapter = new StubDataStructureLocalRepresentationAdapter(); + } + + public XmlWriterFactory(boolean isPretty, + ReferenceAdapter referenceAdapter, + TimeDimensionLocalRepresentationAdapter timeDimensionLocalRepresentationAdapter) { + this.isPretty = isPretty; + this.referenceAdapter = referenceAdapter; + this.timeDimensionLocalRepresentationAdapter = timeDimensionLocalRepresentationAdapter; + } + + public XmlStructureWriter newInstance(OutputStream outputStream, + Map> customStructureWriters) { + var defaultWriters = writers(); + List> writers = new ArrayList<>(); + + for (var writer : defaultWriters) { + writer.getWritableArtefactStructureClass() + .filter(customStructureWriters::containsKey) + .map(customStructureWriters::get) + .ifPresentOrElse(writers::add, () -> writers.add(writer)); + } + return new XmlStructureWriter( + outputStream, + writers, + new HeaderWriter(new DefaultHeaderProvider()), + isPretty + ); + } + + + public XmlStructureWriter newInstance(OutputStream outputStream) { + return new XmlStructureWriter( + outputStream, + this.writers(), + new HeaderWriter(new DefaultHeaderProvider()), + isPretty + ); + } + + protected List> writers() { + var nameableWriter = new NameableWriter(); + var annotableWriter = new AnnotableWriter(); + var urnWriter = new UrnWriter(referenceAdapter); + var commonAttributesWriter = new CommonAttributesWriter(urnWriter); + var linksWriter = new LinksWriter(urnWriter); + + var itemSchemeMapWriter = new ItemSchemeMapWriter(urnWriter); + + var contactWriter = new ContactWriter(); + var orgWriter = new OrganisationWriter(contactWriter, annotableWriter, nameableWriter); + + final var representationWriter = new RepresentationWriter(urnWriter); + + final var codeWriter = new CodeWriterImpl(urnWriter, nameableWriter, annotableWriter); + final var codeListExtensionWriter = new CodeListExtensionWriter(urnWriter); + + final var attributeListWriter = new AttributeListWriter(annotableWriter, representationWriter); + final var dimensionListWriter = new DimensionListWriter(annotableWriter, representationWriter); + final var measureListWriter = new MeasureListWriter(annotableWriter, representationWriter); + final var groupDimensionListWriter = new GroupDimensionListWriter(annotableWriter); + + final var releaseCalenderWriter = new ReleaseCalenderWriter(); + final var memberSelectionWriter = new MemberSelectionWriter(); + + return List.of( + new AgencySchemeWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, orgWriter), + new CategorisationWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, urnWriter), + new CategorySchemeWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter), + new CategorySchemeMapWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, itemSchemeMapWriter), + new CodelistWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, codeWriter, codeListExtensionWriter), + new ConceptSchemeWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, representationWriter), + new ConceptSchemeMapWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, itemSchemeMapWriter), + new DataConstraintWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, releaseCalenderWriter, memberSelectionWriter), + new DataConsumerSchemeWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, orgWriter), + new DataProviderSchemeWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, orgWriter), + new DataStructureDefinitionWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, attributeListWriter, dimensionListWriter, + measureListWriter, groupDimensionListWriter, timeDimensionLocalRepresentationAdapter + ), + new DataflowWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter), + new HierarchyWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, urnWriter), + new HierarchyAssociationWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter), + new MetadataConstraintWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, releaseCalenderWriter, memberSelectionWriter), + new MetadataProviderSchemeWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, orgWriter), + new MetadataProvisionAgreementWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter), + new MetadataStructureDefinitionWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, representationWriter), + new MetadataflowWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter), + new OrganisationSchemeMapWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, itemSchemeMapWriter, urnWriter), + new OrganisationUnitSchemeWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, orgWriter), + new ProcessWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter), + new ProvisionAgreementWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter), + new ReportingTaxonomyWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter), + new ReportingTaxonomyMapWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, itemSchemeMapWriter), + new RepresentationMapWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, urnWriter), + new StructureMapWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter), + new ValueListWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter), + new GeographicCodelistWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, new GeoFeatureSetCodeWriter(urnWriter, + nameableWriter, annotableWriter + ), + codeListExtensionWriter + ), + new GeoGridCodelistWriter(nameableWriter, annotableWriter, commonAttributesWriter, linksWriter, codeListExtensionWriter, + new GridCodeWriter(urnWriter, nameableWriter, annotableWriter) + ) + ); + } +} diff --git a/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlWriterUtils.java b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlWriterUtils.java new file mode 100644 index 0000000..e751c67 --- /dev/null +++ b/sdmx-ml30/src/main/java/com/epam/jsdmx/xml30/structure/writer/XmlWriterUtils.java @@ -0,0 +1,161 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import java.net.URI; +import java.net.URL; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.Component; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.InternationalUri; +import com.epam.jsdmx.infomodel.sdmx30.Version; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.util.Strings; + +public final class XmlWriterUtils { + + private XmlWriterUtils() { + } + + public static void writeInternationalString(InternationalString internationalString, XMLStreamWriter writer, String localName) throws XMLStreamException { + if (internationalString != null) { + Map stringsWithLocales = internationalString.getAll(); + for (Map.Entry stringLocale : stringsWithLocales.entrySet()) { + if (stringLocale != null) { + writer.writeStartElement(localName); + writer.writeAttribute(XmlConstants.XML_LANG, stringLocale.getKey()); + String value = stringLocale.getValue(); + writeCharacters(value, writer); + writer.writeEndElement(); + } + } + } + } + + public static void writeCharacters(String value, XMLStreamWriter writer) throws XMLStreamException { + try { + writer.writeCharacters(Objects.requireNonNullElse(value, Strings.EMPTY)); + } catch (XMLStreamException e) { + if (StringUtils.contains(e.getMessage(), "Invalid white space character (")) { + writer.writeCharacters(removeInvalidChars(value)); + } else { + throw e; + } + } + } + + private static String removeInvalidChars(String value) { + return value.replaceAll("[\\x00-\\x1F\\x7F-\\x9F]", ""); + } + + public static void writeInternationalUri(InternationalUri internationalUri, XMLStreamWriter writer, String localName) throws XMLStreamException { + if (internationalUri != null) { + Map stringsWithLocales = internationalUri.getAll(); + for (Map.Entry stringLocale : stringsWithLocales.entrySet()) { + if (stringLocale != null) { + writer.writeStartElement(localName); + writer.writeAttribute(XmlConstants.XML_LANG, stringLocale.getKey()); + URI value = stringLocale.getValue(); + writeCharacters(value.toString(), writer); + writer.writeEndElement(); + } + } + } + } + + public static void writeVersion(Version version, XMLStreamWriter writer) throws XMLStreamException { + if (version != null) { + writer.writeAttribute(XmlConstants.VERSION, version.getValue()); + } + } + + public static void writeUrn(String urn, XMLStreamWriter writer) throws XMLStreamException { + if (urn != null) { + writer.writeAttribute(XmlConstants.URN, urn); + } + } + + public static void writeUri(URI uri, XMLStreamWriter writer) throws XMLStreamException { + if (uri != null) { + writer.writeAttribute(XmlConstants.URI, uri.toString()); + } + } + + public static void writeUrl(URL url, XMLStreamWriter writer, String urlName) throws XMLStreamException { + if (url != null) { + writer.writeAttribute(urlName, url.toString()); + } + } + + public static void writeInstant(Instant instant, XMLStreamWriter writer, String instanceName) throws XMLStreamException { + if (instant != null) { + writer.writeAttribute(instanceName, instant.toString()); + } + } + + public static void writeMandatoryAttribute(String attribute, XMLStreamWriter writer, String attributeName) throws XMLStreamException { + if (attribute != null) { + writer.writeAttribute(attributeName, attribute); + } else { + throw new IllegalArgumentException(attributeName + XmlConstants.CANNOT_BE_NULL); + } + } + + public static void writeAttributeIfNotNull(String attribute, XMLStreamWriter writer, String attributeName) throws XMLStreamException { + if (attribute != null) { + writer.writeAttribute(attributeName, attribute); + } + } + + public static void writeConceptIdentity(XMLStreamWriter writer, Component component) throws XMLStreamException { + ArtefactReference conceptIdentity = component.getConceptIdentity(); + if (conceptIdentity != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CONCEPT_IDENTITY); + writeCharacters(conceptIdentity.getUrn(), writer); + writer.writeEndElement(); + } + } + + public static void writeConceptRoles(XMLStreamWriter writer, List conceptRoles) throws XMLStreamException { + if (CollectionUtils.isNotEmpty(conceptRoles)) { + for (ArtefactReference artefactReference : conceptRoles) { + if (artefactReference != null) { + writer.writeStartElement(XmlConstants.STRUCTURE + XmlConstants.CONCEPT_ROLE); + writeCharacters(artefactReference.getUrn(), writer); + writer.writeEndElement(); + } + } + } + } + + public static void writeIdUriAttributes(XMLStreamWriter writer, + String id, + URI uri) throws XMLStreamException { + writeMandatoryAttribute(id, writer, XmlConstants.ID); + writeUri(uri, writer); + } + + public static void writeArtefactReference(XMLStreamWriter writer, String artefactReferenceName, String reference) throws XMLStreamException { + writer.writeStartElement(XmlConstants.STRUCTURE + artefactReferenceName); + writeCharacters(reference, writer); + writer.writeEndElement(); + } + + public static String instantToDateString(Instant time) { + DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE.withZone(ZoneId.systemDefault()); + if (time != null) { + return formatter.format(time); + } + return null; + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/data/StreamingXmlDataWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/data/StreamingXmlDataWriterTest.java new file mode 100644 index 0000000..171b998 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/data/StreamingXmlDataWriterTest.java @@ -0,0 +1,858 @@ +package com.epam.jsdmx.xml30.data; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponent; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponentImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.FacetType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.Measure; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeRefImpl; +import com.epam.jsdmx.infomodel.sdmx30.ObservationRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; +import com.epam.jsdmx.serializer.sdmx30.common.ActionType; +import com.epam.jsdmx.serializer.sdmx30.common.DatasetHeader; +import com.epam.jsdmx.serializer.sdmx30.common.DatasetHeaderImpl; +import com.epam.jsdmx.serializer.sdmx30.common.DatasetStructureReferenceImpl; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultHeaderProvider; +import com.epam.jsdmx.serializer.sdmx30.common.Header; +import com.epam.jsdmx.serializer.sdmx30.common.SimpleMetadataAttributeValue; +import com.epam.jsdmx.xml30.structure.writer.HeaderWriter; + +import lombok.SneakyThrows; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class StreamingXmlDataWriterTest { + + public static final String DATASET_XML = "/xml/dataquery/xml_3.0_dataset.xml"; + public static final String DATASET_FLAT_XML = "/xml/dataquery/xml_3.0_dataset_flat.xml"; + public static final String DATASET_ATTR_XML = "/xml/dataquery/xml_3.0_data_query_dataset_atts.xml"; + public static final String SERIES_XML = "/xml/dataquery/xml_3.0_data_query_series.xml"; + public static final String SERIES_MULTI_XML = "/xml/dataquery/xml_3.0_data_query_series_multi.xml"; + public static final String SERIES_OBS_XML = "/xml/dataquery/xml_3.0_data_query_series_and_obs.xml"; + public static final String GROUPS_XML = "/xml/dataquery/xml_3.0_data_query_groups.xml"; + public static final String GROUPS_SERIES_XML = "/xml/dataquery/xml_3.0_data_query_groups_series.xml"; + public static final String GROUPS_OBS_XML = "/xml/dataquery/xml_3.0_data_query_groups_obs.xml"; + public static final String GROUPS_META_XML = "/xml/dataquery/xml_3.0_data_query_groups_meta.xml"; + public static final String OBS_XML = "/xml/dataquery/xml_3.0_data_query_obs.xml"; + public static final String MULTILINGUAL_ATTS_XML = "/xml/dataquery/xml_3.0_data_query_multiling_atts.xml"; + public static final String ATTS_SERIES_XML = "/xml/dataquery/xml_3.0_data_query_atts_series.xml"; + public static final String ATTS_OBS_XML = "/xml/dataquery/xml_3.0_data_query_atts_obs.xml"; + public static final String MULTILINGUAL_ATTS_OBS_XML = "/xml/dataquery/xml_3.0_data_query_multiling_atts_obs.xml"; + public static final String META_XML = "/xml/dataquery/xml_3.0_data_query_meta.xml"; + public static final String META2_XML = "/xml/dataquery/xml_3.0_data_query_meta2.xml"; + public static final String META_FLAT_XML = "/xml/dataquery/xml_3.0_data_query_meta_flat.xml"; + public static final String META_MULTI_XML = "/xml/dataquery/xml_3.0_data_query_meta_multi.xml"; + + private StreamingXmlDataWriter streamingXmlDataWriter; + private final DefaultHeaderProvider defaultHeaderProvider = mock(DefaultHeaderProvider.class); + HeaderWriter headerWriter = new HeaderWriter(defaultHeaderProvider); + + @BeforeEach + @SneakyThrows + void setup() { + Header header = new Header(); + header.setId("HED1"); + header.setName(new InternationalString("HeaderTest")); + header.setTest(true); + header.setReceivers(List.of(new Party("id", new InternationalString("str")))); + header.setSender(new Party("id", new InternationalString())); + header.setPrepared(Instant.parse("2023-04-17T10:11:16Z")); + when(defaultHeaderProvider.provide()).thenReturn(header); + } + + @Test + void writeDatasets() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeader(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute1"); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute2"); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute3"); + SimpleMetadataAttributeValue metadataAttributeValue = new SimpleMetadataAttributeValue(); + metadataAttributeValue.setId("METAATTR"); + metadataAttributeValue.setValues(List.of("dataset_attr")); + streamingXmlDataWriter.writeMetaData(metadataAttributeValue); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(DATASET_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeFlatDatasets() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeaderAllDimensions(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute1"); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute2"); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute3"); + SimpleMetadataAttributeValue metadataAttributeValue = new SimpleMetadataAttributeValue(); + metadataAttributeValue.setId("METAATTR"); + metadataAttributeValue.setValues(List.of("dataset_attr")); + streamingXmlDataWriter.writeMetaData(metadataAttributeValue); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(DATASET_FLAT_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeDatasetAtts() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeader(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + streamingXmlDataWriter.writeAttribute("ATTR2", List.of("attribute2", "attribute3")); + SimpleMetadataAttributeValue metadataAttributeValue = new SimpleMetadataAttributeValue(); + metadataAttributeValue.setId("METAATTR"); + metadataAttributeValue.setValues(List.of("dataset_attr")); + streamingXmlDataWriter.writeMetaData(metadataAttributeValue); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(DATASET_ATTR_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeSeries() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeader(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension"); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + streamingXmlDataWriter.writeObservation("TIME_PERIOD", "2020", Map.of("MM", "measure"), null); + streamingXmlDataWriter.writeAttribute("ATTR2", "attribute"); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension2"); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute2"); + streamingXmlDataWriter.writeObservation(null, Map.of("MM2", "measure"), null); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(SERIES_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeSeriesMulti() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeader(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension"); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + streamingXmlDataWriter.writeAttribute("MULT", List.of("mult_value_1", "mult_value_2")); + streamingXmlDataWriter.writeObservation("TIME_PERIOD", "2020", Map.of("MM", "measure"), null); + streamingXmlDataWriter.writeAttribute("ATTR2", "attribute"); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension2"); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute2"); + streamingXmlDataWriter.writeAttribute("MULT", List.of("mult_value_3", "mult_value_4")); + streamingXmlDataWriter.writeObservation(null, Map.of("MM2", "measure"), null); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(SERIES_MULTI_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeSeriesAndObs() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeader(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension"); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + streamingXmlDataWriter.writeObservation("TIME_PERIOD", "2020", Map.of("MM", "measure"), null); + streamingXmlDataWriter.writeAttribute("MULT", "mult1"); + streamingXmlDataWriter.writeAttribute("ATTR2", "attribute"); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension2"); + streamingXmlDataWriter.writeObservation(null, Map.of("MM2", "measure"), null); + streamingXmlDataWriter.writeAttribute("ATTR2", "attribute22"); + streamingXmlDataWriter.writeAttribute("MULT", List.of("mult_value_1", "mult_value_2")); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(SERIES_OBS_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeGroups() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeader(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.startGroup(); + streamingXmlDataWriter.writeGroupComponent("DIM", "dimension"); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + streamingXmlDataWriter.startGroup(); + streamingXmlDataWriter.writeGroupComponent("DIM2", "dimension2"); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute2"); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(GROUPS_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeObs() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeaderAllDimensions(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension"); + streamingXmlDataWriter.writeObservation("TIME_PERIOD", "2020", Map.of("MM", "measure"), null); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute2"); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(OBS_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeAtts() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeader(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension"); + streamingXmlDataWriter.writeAttribute("ATTR2", "attribute2"); + streamingXmlDataWriter.writeObservation("TIME_PERIOD", "2020", Map.of("MM", "measure"), null); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(ATTS_SERIES_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeMultilingualAttribute() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeader(); + InternationalString internationalString = new InternationalString(Map.of("en", "english", "fr", "french")); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + streamingXmlDataWriter.writeAttribute("METAATTR", internationalString); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension"); + streamingXmlDataWriter.writeAttribute("ATTR2", internationalString); + streamingXmlDataWriter.writeAttribute("METAATTR_SERIES", internationalString); + streamingXmlDataWriter.writeObservation("TIME_PERIOD", "2020", Map.of("MM", "measure"), null); + streamingXmlDataWriter.writeAttribute("METAATTR_OBS", internationalString); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(MULTILINGUAL_ATTS_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeAttsFlat() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeaderAllDimensions(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension"); + streamingXmlDataWriter.writeAttribute("ATTR2", "attribute2"); + streamingXmlDataWriter.writeObservation("TIME_PERIOD", "2020", Map.of("MM", "measure"), null); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(ATTS_OBS_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeMultilingualAttributeFlat() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeaderAllDimensions(); + InternationalString internationalString = new InternationalString(Map.of("en", "english", "fr", "french")); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension"); + streamingXmlDataWriter.writeObservation("TIME_PERIOD", "2020", Map.of("MM", "measure"), null); + streamingXmlDataWriter.writeInternationalAttributes("ATTR2", List.of(internationalString, internationalString)); + streamingXmlDataWriter.writeAttribute("ATT23R", List.of("attribute")); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(MULTILINGUAL_ATTS_OBS_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeGroupSeriesAtts() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeader(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + streamingXmlDataWriter.startGroup(); + streamingXmlDataWriter.writeGroupComponent("DIM", "dimension"); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + streamingXmlDataWriter.startGroup(); + streamingXmlDataWriter.writeGroupComponent("DIM2", "dimension2"); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute2"); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension"); + streamingXmlDataWriter.writeAttribute("ATTR2", "attribute2"); + streamingXmlDataWriter.writeObservation("TIME_PERIOD", "2020", Map.of("MM", "measure"), null); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(GROUPS_SERIES_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeGroupObsAtts() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeaderAllDimensions(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + streamingXmlDataWriter.startGroup(); + streamingXmlDataWriter.writeGroupComponent("DIM", "dimension"); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + streamingXmlDataWriter.startGroup(); + streamingXmlDataWriter.writeGroupComponent("DIM2", "dimension2"); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute2"); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension_"); + streamingXmlDataWriter.writeSeriesComponent("DIM2", "dimension__"); + streamingXmlDataWriter.writeObservation("TIME_PERIOD", "2020", Map.of("MM", "measure"), null); + streamingXmlDataWriter.writeAttribute("ATTR1", "P"); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(GROUPS_OBS_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeGroupMetaAtts() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeader(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.startGroup(); + streamingXmlDataWriter.writeGroupComponent("DIM", "dimension"); + SimpleMetadataAttributeValue metadataAttributeValue = new SimpleMetadataAttributeValue(); + metadataAttributeValue.setId("METAATTR"); + metadataAttributeValue.setValues(List.of("attr")); + streamingXmlDataWriter.writeMetaData(metadataAttributeValue); + streamingXmlDataWriter.startGroup(); + streamingXmlDataWriter.writeGroupComponent("DIM2", "dimension2"); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute2"); + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension"); + streamingXmlDataWriter.writeAttribute("ATTR2", "attribute2"); + streamingXmlDataWriter.writeObservation("TIME_PERIOD", "2020", Map.of("MM", "measure"), null); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(GROUPS_META_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeMetaByWriteMetaDataMethod() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeader(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + + SimpleMetadataAttributeValue metadataAttributeValue = new SimpleMetadataAttributeValue(); + metadataAttributeValue.setId("Multi"); + metadataAttributeValue.setValues(List.of("multi")); + streamingXmlDataWriter.writeMetaData(metadataAttributeValue); + + metadataAttributeValue.setId("METAATTR"); + metadataAttributeValue.setValues(List.of("dataset_attr")); + streamingXmlDataWriter.writeMetaData(metadataAttributeValue); + + streamingXmlDataWriter.startGroup(); + streamingXmlDataWriter.writeGroupComponent("DIM", "dimension"); + metadataAttributeValue.setId("METAATTR"); + metadataAttributeValue.setValues(List.of("gr_attr")); + streamingXmlDataWriter.writeMetaData(metadataAttributeValue); + + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension"); + metadataAttributeValue.setId("METAATTR_SERIES"); + metadataAttributeValue.setValues(List.of("att_series")); + streamingXmlDataWriter.writeMetaData(metadataAttributeValue); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + + streamingXmlDataWriter.writeObservation("TIME_PERIOD", "2020", Map.of("MM", "measure"), null); + streamingXmlDataWriter.writeAttribute("ATTR2", "obs_attribute"); + metadataAttributeValue.setId("METAATTR_OBS"); + metadataAttributeValue.setValues(List.of("att_obs", "att_obs2")); + streamingXmlDataWriter.writeMetaData(metadataAttributeValue); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(META_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeMetaByWriteAttributeMethod() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeader(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + streamingXmlDataWriter.writeAttribute("Multi", "multi"); + streamingXmlDataWriter.writeAttribute("METAATTR", "dataset_attr"); + + streamingXmlDataWriter.startGroup(); + streamingXmlDataWriter.writeGroupComponent("DIM", "dimension"); + streamingXmlDataWriter.writeAttribute("METAATTR", "gr_attr"); + + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension"); + streamingXmlDataWriter.writeAttribute("METAATTR_SERIES", List.of("att_series")); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + + streamingXmlDataWriter.writeObservation("TIME_PERIOD", "2020", Map.of("MM", "measure"), null); + streamingXmlDataWriter.writeAttribute("METAATTR_OBS", List.of("att_obs", "att_obs2")); + streamingXmlDataWriter.writeAttribute("ATTR2", "obs_attribute"); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(META2_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeMetaFlat() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeaderAllDimensions(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + + SimpleMetadataAttributeValue metadataAttributeValue = new SimpleMetadataAttributeValue(); + metadataAttributeValue.setId("Multi"); + metadataAttributeValue.setValues(List.of("multi")); + streamingXmlDataWriter.writeMetaData(metadataAttributeValue); + + metadataAttributeValue.setId("METAATTR"); + metadataAttributeValue.setValues(List.of("dataset_attr")); + streamingXmlDataWriter.writeMetaData(metadataAttributeValue); + + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension"); + metadataAttributeValue.setId("METAATTR_SERIES"); + metadataAttributeValue.setValues(List.of("att_series")); + streamingXmlDataWriter.writeMetaData(metadataAttributeValue); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + + streamingXmlDataWriter.writeObservation(null, Map.of("MM", "measure"), null); + metadataAttributeValue.setId("METAATTR_OBS"); + metadataAttributeValue.setValues(List.of("att_obs", "att_obs2")); + streamingXmlDataWriter.writeMetaData(metadataAttributeValue); + + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(META_FLAT_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeMultiMeta() throws XMLStreamException, IOException, SAXException { + Artefacts artefacts = getArtefacts(); + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + DatasetHeader datasetHeader = getDatasetHeaderAllDimensions(); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.startDataset(null, artefacts, datasetHeader); + + SimpleMetadataAttributeValue metadataAttributeValue = new SimpleMetadataAttributeValue(); + metadataAttributeValue.setId("METAATTR"); + metadataAttributeValue.setValues(List.of("dataset_attr", "dataset_attr2")); + streamingXmlDataWriter.writeMetaData(metadataAttributeValue); + + streamingXmlDataWriter.startSeries(); + streamingXmlDataWriter.writeSeriesComponent("DIM", "dimension"); + streamingXmlDataWriter.writeAttribute("ATTR", "attribute"); + streamingXmlDataWriter.writeObservation(null, Map.of("MM", "measure"), null); + metadataAttributeValue.setValues(List.of("meta1", "meta2")); + streamingXmlDataWriter.writeMetaData(metadataAttributeValue); + streamingXmlDataWriter.writeAttribute("MULT", List.of("mult_value_1", "mult_value_2")); + streamingXmlDataWriter.close(); + InputStream resourceAsStream = StreamingXmlDataWriterTest.class.getResourceAsStream(META_MULTI_XML); + assert resourceAsStream != null; + String expected = new String(resourceAsStream.readAllBytes()); + String actual = output.toString(); + System.out.println(actual); + assertXMLEqual(expected, actual); + } + + @Test + void writeNothingAndClose() throws XMLStreamException { + ByteArrayOutputStream output = new ByteArrayOutputStream(1024); + XMLUnit.setIgnoreWhitespace(true); + XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter( + new OutputStreamWriter(output, StandardCharsets.UTF_8)); + streamingXmlDataWriter = new StreamingXmlDataWriter(xmlStreamWriter, headerWriter); + streamingXmlDataWriter.close(); + String actual = output.toString(); + assertThat(actual).isBlank(); + } + + public static DatasetHeader getDatasetHeader() { + return DatasetHeaderImpl.builder() + .datasetId("1") + .action(ActionType.INFORMATION) + .datasetStructureReference(new DatasetStructureReferenceImpl( + new IdentifiableArtefactReferenceImpl( + "id1", + "agnc1", + "1.0", + StructureClassImpl.DATA_STRUCTURE, + "SID" + ), + ActionType.INFORMATION, + "dd" + )) + .validFrom(Instant.parse("2022-05-17T10:11:16Z")) + .validTo(Instant.parse("2023-06-17T11:10:16Z")) + .build(); + } + + public static DatasetHeader getDatasetHeaderAllDimensions() { + return DatasetHeaderImpl.builder() + .datasetId("1") + .action(ActionType.INFORMATION) + .datasetStructureReference(new DatasetStructureReferenceImpl( + new IdentifiableArtefactReferenceImpl( + "id1", + "agnc1", + "1.0", + StructureClassImpl.DATA_STRUCTURE, + "SID" + ), + ActionType.INFORMATION, + "AllDimensions" + )) + .validFrom(Instant.parse("2022-05-17T10:11:16Z")) + .validTo(Instant.parse("2023-06-17T11:10:16Z")) + .build(); + } + + private static DataStructureDefinitionImpl getDataStructureDefinition() { + DataStructureDefinitionImpl dsd = new DataStructureDefinitionImpl(); + dsd.setId("DSD1"); + dsd.setOrganizationId("QH"); + dsd.setVersion(Version.createFromString("1.0.0")); + dsd.setName(new InternationalString("DSD")); + DimensionDescriptorImpl dimensionDescriptor = new DimensionDescriptorImpl(); + List dimensionComponents = new ArrayList<>(); + DimensionComponentImpl dimensionComponent = new DimensionImpl(); + dimensionComponent.setId("DIM"); + dimensionComponent.setConceptIdentity(new IdentifiableArtefactReferenceImpl( + "CS1", "IMF", "1.0.0", StructureClassImpl.CONCEPT, "DIM" + )); + dimensionComponents.add(dimensionComponent); + DimensionComponentImpl dimensionComponent2 = new DimensionImpl(); + dimensionComponent2.setId("DIM2"); + dimensionComponent2.setConceptIdentity(new IdentifiableArtefactReferenceImpl( + "CS1", "IMF", "1.0.0", StructureClassImpl.CONCEPT, "DIM2" + )); + dimensionComponents.add(dimensionComponent2); + dimensionDescriptor.setComponents(dimensionComponents); + dsd.setDimensionDescriptor(dimensionDescriptor); + AttributeDescriptorImpl attributeDescriptor = new AttributeDescriptorImpl(); + attributeDescriptor.setId("AD"); + DataAttributeImpl dataAttribute = new DataAttributeImpl(); + dataAttribute.setId("ATTR"); + dataAttribute.setConceptIdentity(new IdentifiableArtefactReferenceImpl( + "CS1", "IMF", "1.0.0", StructureClassImpl.CONCEPT_SCHEME, "ATTR" + )); + dataAttribute.setMaxOccurs(1); + DataAttributeImpl dataAttribute2 = new DataAttributeImpl(); + dataAttribute2.setId("ATTR2"); + dataAttribute2.setConceptIdentity(new IdentifiableArtefactReferenceImpl( + "CS1", "IMF", "1.0.0", StructureClassImpl.CONCEPT_SCHEME, "ATTR2" + )); + dataAttribute2.setMaxOccurs(1); + DataAttributeImpl dataAttribute3 = new DataAttributeImpl(); + dataAttribute3.setId("MULT"); + dataAttribute3.setConceptIdentity(new IdentifiableArtefactReferenceImpl( + "CS1", "IMF", "1.0.0", StructureClassImpl.CONCEPT_SCHEME, "MULT" + )); + dataAttribute3.setMaxOccurs(2); + attributeDescriptor.setComponents(List.of(dataAttribute, dataAttribute2, dataAttribute3)); + MetadataAttributeRefImpl metaAttributeRef = new MetadataAttributeRefImpl(); + metaAttributeRef.setId("METAATTR_OBS"); + metaAttributeRef.setMetadataRelationship(new ObservationRelationshipImpl()); + MetadataAttributeRefImpl metaAttributeRef2 = new MetadataAttributeRefImpl(); + metaAttributeRef2.setId("METAATTR_SERIES"); + DimensionRelationshipImpl dimensionRelationship = new DimensionRelationshipImpl(); + dimensionRelationship.setDimensions(List.of("DIM1", "DIM2")); + metaAttributeRef2.setMetadataRelationship(dimensionRelationship); + MetadataAttributeRefImpl metaAttributeRef3 = new MetadataAttributeRefImpl(); + metaAttributeRef3.setId("METAATTR"); + metaAttributeRef3.setMetadataRelationship(null); + attributeDescriptor.setMetadataAttributes(List.of(metaAttributeRef, metaAttributeRef2, metaAttributeRef3)); + dsd.setAttributeDescriptor(attributeDescriptor); + MeasureDescriptorImpl measureDescriptor = new MeasureDescriptorImpl(); + measureDescriptor.setId("MES"); + List measures = new ArrayList<>(); + MeasureImpl measure = new MeasureImpl(); + measure.setId("MM"); + measure.setConceptIdentity(new IdentifiableArtefactReferenceImpl( + "CS1", "IMF", "1.0.0", StructureClassImpl.CONCEPT_SCHEME, "MM" + )); + measures.add(measure); + measureDescriptor.setComponents(measures); + dsd.setMeasureDescriptor(measureDescriptor); + return dsd; + } + + private static ConceptSchemeImpl getConceptScheme() { + ConceptSchemeImpl conceptScheme = new ConceptSchemeImpl(); + conceptScheme.setId("CS1"); + conceptScheme.setOrganizationId("IMF"); + + ConceptImpl concept = TestUtils.getConceptWithEnumeratedRepresentation("DIM", "CL-1", "COD1"); + concept.setName(new InternationalString(prepareLocaleStrings("dim_name", "діменшин"))); + + ConceptImpl concept2 = TestUtils.getConceptWithEnumeratedRepresentation("ATTR", "CL-1", "COD"); + concept2.setName(new InternationalString(prepareLocaleStrings("attr_name", "атрібут"))); + + ConceptImpl concept3 = TestUtils.getConceptWithEnumeratedRepresentation("MM", "CL-1", "COD"); + concept3.setName(new InternationalString(prepareLocaleStrings("meas_name", "межур"))); + + ConceptImpl concept4 = TestUtils.getConceptWithBaseRepresentation("MULT", FacetType.IS_MULTILINGUAL, FacetValueType.STRING); + concept4.setId("MULT"); + concept4.setName(new InternationalString(prepareLocaleStrings("multi_name", "мульті"))); + + conceptScheme.setItems(List.of(concept, concept2, concept3, concept4)); + conceptScheme.setVersion(Version.createFromString("1.0.0")); + return conceptScheme; + } + + private static Map prepareLocaleStrings(String valueInEnglish, String valueInUkrainian) { + Map localeStrings = new HashMap<>(); + localeStrings.put("en", valueInEnglish); + localeStrings.put("uk", valueInUkrainian); + return localeStrings; + } + + private static CodelistImpl getCodelist() { + CodelistImpl codelist = TestUtils.getCodelist("CL-1"); + Map langs = new HashMap<>(); + langs.put("en", "Some code"); + langs.put("fr", "Quelque code"); + codelist.setName(new InternationalString(langs)); + Map langsDesc = new HashMap<>(); + langsDesc.put("en", "Some desc"); + langsDesc.put("fr", "Quelque desc"); + codelist.setDescription(new InternationalString(langsDesc)); + CodeImpl code = TestUtils.getCode("COD1"); + Map langsCode = new HashMap<>(); + langsCode.put("en", "code"); + langsCode.put("fr", " codee"); + code.setName(new InternationalString(langsCode)); + CodeImpl code2 = TestUtils.getCode("DIM"); + codelist.setItems(List.of(code, code2)); + return codelist; + } + + private static Artefacts getArtefacts() { + CodelistImpl codelist = getCodelist(); + ConceptSchemeImpl conceptScheme = getConceptScheme(); + DataStructureDefinitionImpl dsd = getDataStructureDefinition(); + DataflowImpl dataflow = TestUtils.getDataflow("DSD1", "DFlow"); + Artefacts artefacts = new ArtefactsImpl(); + artefacts.getCodelists().add(codelist); + artefacts.getConceptSchemes().add(conceptScheme); + artefacts.getDataStructures().add(dsd); + artefacts.getDataflows().add(dataflow); + return artefacts; + } + +} \ No newline at end of file diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/data/TestUtils.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/data/TestUtils.java new file mode 100644 index 0000000..e4dc379 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/data/TestUtils.java @@ -0,0 +1,328 @@ +package com.epam.jsdmx.xml30.data; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseFacetImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseTextFormatRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponent; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponentImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.EnumeratedRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.Facet; +import com.epam.jsdmx.infomodel.sdmx30.FacetType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.Measure; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinition; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; +import com.epam.jsdmx.infomodel.sdmx30.VersionReference; +import com.epam.jsdmx.serializer.sdmx30.common.ActionType; +import com.epam.jsdmx.serializer.sdmx30.common.DatasetHeader; +import com.epam.jsdmx.serializer.sdmx30.common.DatasetHeaderImpl; + +import org.apache.commons.lang.StringUtils; + +public class TestUtils { + + public static final String ORGANISATION_ID = "IMF"; + public static final String VERSION = "1.0.0"; + + public static DatasetHeader getDatasetHeader() { + return DatasetHeaderImpl.builder() + .datasetId("1") + .action(ActionType.INFORMATION) + .build(); + } + + private static ConceptSchemeImpl getConceptSchemeAttributes(String conceptSchemeId, + String concept1Id, + String concept2Id, + String artefactRef1Id, + String artefactRef2Id) { + ConceptSchemeImpl conceptScheme = new ConceptSchemeImpl(); + conceptScheme.setId(conceptSchemeId); + conceptScheme.setOrganizationId(ORGANISATION_ID); + ConceptImpl concept = getConceptWithEnumeratedRepresentation(concept1Id, artefactRef1Id, StringUtils.EMPTY); + ConceptImpl concept2 = getConceptWithEnumeratedRepresentation(concept2Id, artefactRef2Id, StringUtils.EMPTY); + conceptScheme.setItems(List.of(concept, concept2)); + conceptScheme.setVersion(Version.createFromString(VERSION)); + return conceptScheme; + } + + public static ConceptImpl getConceptWithEnumeratedRepresentation(String conceptId, String artefactRefId, String artefactItemId) { + ConceptImpl concept = getConcept(conceptId); + IdentifiableArtefactReferenceImpl artefactReference = getIdentifiableArtefactReference(artefactRefId, artefactItemId); + EnumeratedRepresentationImpl enumeratedRepresentation = new EnumeratedRepresentationImpl(artefactReference); + concept.setCoreRepresentation(enumeratedRepresentation); + return concept; + } + + public static ConceptImpl getConceptWithBaseRepresentation(String conceptId, FacetType facetType, FacetValueType facetValueType) { + ConceptImpl concept = getConcept(conceptId); + BaseTextFormatRepresentationImpl baseTextFormatRepresentation = new BaseTextFormatRepresentationImpl(facetValueType); + + if (facetType != null) { + Iterator iterator = baseTextFormatRepresentation.nonEnumerated().iterator(); + if (iterator.hasNext()) { + BaseFacetImpl next = (BaseFacetImpl) iterator.next(); + next.setType(facetType); + } + } + + concept.setCoreRepresentation(baseTextFormatRepresentation); + return concept; + } + + private static IdentifiableArtefactReferenceImpl getIdentifiableArtefactReference(String artefactRefId, + String artefactItemId) { + IdentifiableArtefactReferenceImpl artefactReference = new IdentifiableArtefactReferenceImpl(); + artefactReference.setOrganisationId(ORGANISATION_ID); + artefactReference.setVersion(VersionReference.createFromString(VERSION)); + artefactReference.setId(artefactRefId); + artefactReference.setStructureClass(StructureClassImpl.CODELIST); + if (!artefactItemId.equals(StringUtils.EMPTY)) { + artefactReference.setItemId(artefactItemId); + } + return artefactReference; + } + + private static ConceptImpl getConcept(String concept1Id) { + ConceptImpl concept = new ConceptImpl(); + concept.setId(concept1Id); + concept.setName(new InternationalString(concept1Id)); + return concept; + } + + public static Artefacts getArtefacts() { + CodelistImpl codelist_Country = createCountryCodelist(); + CodelistImpl codelist_Indicators = createIndicatorCodelist(); + CodelistImpl codelist_Units = createUnitCodelist(); + CodelistImpl codelist_ATTR_1 = createAttr1Codelist(); + CodelistImpl codelist_ATTR_2 = createAttr2Codelist(); + ConceptSchemeImpl conceptSchemeDim = getConceptSchemeDimensions("CS1"); + ConceptSchemeImpl conceptSchemeAttr = getConceptSchemeAttributes( + "CS2", + "attr_val1", + "attr_val2", + "CL-ATTR_1", + "CL-ATTR_2" + ); + DataStructureDefinitionImpl dsd = getDataStructureDefinition("DSD1", "Countries", + "Indicators", + "Units", "MES", + "CS1", + "CS2" + ); + DataflowImpl dataflow = getDataflow("DSD1", "DFlow"); + Artefacts artefacts = new ArtefactsImpl(); + artefacts.getCodelists().addAll(List.of( + codelist_Country, + codelist_Indicators, + codelist_Units, + codelist_ATTR_1, + codelist_ATTR_2 + )); + artefacts.getConceptSchemes().addAll(List.of(conceptSchemeDim, conceptSchemeAttr)); + artefacts.getDataStructures().add(dsd); + artefacts.getDataflows().add(dataflow); + return artefacts; + } + + public static DataflowImpl getDataflow(String dsdId, String dataflowId) { + DataflowImpl dataflow = new DataflowImpl(); + dataflow.setId(dataflowId); + dataflow.setVersion(Version.createFromString("1.0")); + dataflow.setOrganizationId("QH"); + dataflow.setName(new InternationalString("DataFlow")); + dataflow.setStructure(new IdentifiableArtefactReferenceImpl(dsdId, "QH", VERSION, + StructureClassImpl.DATA_STRUCTURE, dsdId + )); + return dataflow; + } + + public static DataStructureDefinitionImpl getDataStructureDefinition(String dsdId, + String dimComponent1Id, + String dimComponent2Id, + String dimComponent3Id, + String measureDescrId, + String conceptScheme1Id, + String conceptScheme2Id + ) { + DataStructureDefinitionImpl dsd = new DataStructureDefinitionImpl(); + dsd.setId(dsdId); + dsd.setOrganizationId("QH"); + dsd.setVersion(Version.createFromString(VERSION)); + dsd.setName(new InternationalString("DSD")); + setDimensionDescriptor(dimComponent1Id, dimComponent2Id, dimComponent3Id, conceptScheme1Id, dsd); + setAttributeDescriptor(conceptScheme2Id, dsd); + setMeasureDescriptor(conceptScheme1Id, dsd, measureDescrId, "Obs_value"); + return dsd; + } + + private static void setMeasureDescriptor(String conceptScheme1Id, + DataStructureDefinitionImpl dsd, + String measureDescriptorId, + String measureId) { + MeasureDescriptorImpl measureDescriptor = new MeasureDescriptorImpl(); + measureDescriptor.setId(measureDescriptorId); + List measures = new ArrayList<>(); + MeasureImpl measure = new MeasureImpl(); + measure.setId(measureId); + measure.setConceptIdentity(new IdentifiableArtefactReferenceImpl( + conceptScheme1Id, ORGANISATION_ID, VERSION, StructureClassImpl.CONCEPT_SCHEME, "obs_value" + )); + measures.add(measure); + measureDescriptor.setComponents(measures); + dsd.setMeasureDescriptor(measureDescriptor); + } + + private static void setAttributeDescriptor(String conceptScheme2Id, DataStructureDefinitionImpl dsd) { + AttributeDescriptorImpl attributeDescriptor = new AttributeDescriptorImpl(); + attributeDescriptor.setId("AD"); + DataAttributeImpl dataAttribute1 = getDataAttribute("ATTR1", "attr_val1", conceptScheme2Id); + DataAttributeImpl dataAttribute2 = getDataAttribute("ATTR2", "attr_val2", conceptScheme2Id); + attributeDescriptor.setComponents(List.of(dataAttribute1, dataAttribute2)); + dsd.setAttributeDescriptor(attributeDescriptor); + } + + private static void setDimensionDescriptor(String dimComponent1Id, + String dimComponent2Id, + String dimComponent3Id, + String conceptScheme1Id, + DataStructureDefinitionImpl dsd) { + DimensionDescriptorImpl dimensionDescriptor = new DimensionDescriptorImpl(); + List dimensionComponents = new ArrayList<>(); + DimensionComponentImpl dimensionComponent1 = getDimensionComponent(dimComponent1Id, conceptScheme1Id); + DimensionComponentImpl dimensionComponent2 = getDimensionComponent(dimComponent2Id, conceptScheme1Id); + DimensionComponentImpl dimensionComponent3 = getDimensionComponent(dimComponent3Id, conceptScheme1Id); + dimensionComponents.add(dimensionComponent1); + dimensionComponents.add(dimensionComponent2); + dimensionComponents.add(dimensionComponent3); + dimensionDescriptor.setComponents(dimensionComponents); + dsd.setDimensionDescriptor(dimensionDescriptor); + } + + public static DataAttributeImpl getDataAttribute(String attrId, String attrVal, String conceptschemeId) { + DataAttributeImpl dataAttribute = new DataAttributeImpl(); + dataAttribute.setId(attrId); + dataAttribute.setConceptIdentity(new IdentifiableArtefactReferenceImpl( + conceptschemeId, ORGANISATION_ID, VERSION, StructureClassImpl.CONCEPT_SCHEME, attrVal + )); + return dataAttribute; + } + + private static DimensionComponentImpl getDimensionComponent(String dimComponent1Id, String conceptScheme1Id) { + DimensionComponentImpl dimensionComponent = new DimensionImpl(); + dimensionComponent.setId(dimComponent1Id); + dimensionComponent.setConceptIdentity(new IdentifiableArtefactReferenceImpl( + conceptScheme1Id, ORGANISATION_ID, VERSION, StructureClassImpl.CONCEPT, dimComponent1Id + )); + return dimensionComponent; + } + + private static ConceptSchemeImpl getConceptSchemeDimensions(String conceptSchemeId) { + ConceptSchemeImpl conceptScheme = new ConceptSchemeImpl(); + conceptScheme.setId(conceptSchemeId); + conceptScheme.setOrganizationId(ORGANISATION_ID); + ConceptImpl concept = getConceptWithEnumeratedRepresentation("Countries", "CL-Countries", StringUtils.EMPTY); + ConceptImpl concept2 = getConceptWithEnumeratedRepresentation("Indicators", "CL-Indicators", StringUtils.EMPTY); + ConceptImpl concept3 = getConceptWithEnumeratedRepresentation("Units", "CL-Units", StringUtils.EMPTY); + ConceptImpl concept4 = getConceptWithBaseRepresentation("obs_value", null, FacetValueType.STRING); + conceptScheme.setItems(List.of(concept, concept2, concept3, concept4)); + conceptScheme.setVersion(Version.createFromString(VERSION)); + return conceptScheme; + } + + public static CodelistImpl createCountryCodelist() { + CodelistImpl codelist = getCodelist("CL-Countries"); + CodeImpl code = getCode("111"); + CodeImpl code2 = getCode("112"); + CodeImpl code3 = getCode("110"); + codelist.setItems(List.of(code, code2, code3)); + return codelist; + } + + public static CodeImpl getCode(String id) { + CodeImpl code = new CodeImpl(); + code.setId(id); + return code; + } + + public static CodelistImpl getCodelist(String id) { + CodelistImpl codelist = new CodelistImpl(); + codelist.setId(id); + codelist.setOrganizationId(ORGANISATION_ID); + codelist.setVersion(Version.createFromString(VERSION)); + return codelist; + } + + public static CodelistImpl createIndicatorCodelist() { + CodelistImpl codelist = getCodelist("CL-Indicators"); + CodeImpl code = getCode("LP"); + CodeImpl code2 = getCode("KP"); + codelist.setItems(List.of(code, code2)); + return codelist; + } + + public static CodelistImpl createUnitCodelist() { + CodelistImpl codelist = getCodelist("CL-Units"); + CodeImpl code = getCode("Person"); + CodeImpl code2 = getCode("No_Person"); + codelist.setItems(List.of(code, code2)); + return codelist; + } + + public static CodelistImpl createAttr1Codelist() { + CodelistImpl codelist = getCodelist("CL-ATTR_1"); + CodeImpl code = getCode("K"); + CodeImpl code2 = getCode("P"); + codelist.setItems(List.of(code, code2)); + return codelist; + } + + public static CodelistImpl createAttr2Codelist() { + CodelistImpl codelist = getCodelist("CL-ATTR_2"); + CodeImpl code = getCode("L"); + CodeImpl code2 = getCode("N"); + codelist.setItems(List.of(code, code2)); + return codelist; + } + + public static MetadataStructureDefinition createMdsd() { + MetadataStructureDefinitionImpl mdsd = new MetadataStructureDefinitionImpl(); + mdsd.setId("MDSD1"); + mdsd.setVersion(Version.createFromString("1.0.0")); + mdsd.setOrganizationId("IMF"); + mdsd.setName(new InternationalString("MDSD")); + MetadataAttributeDescriptor attributeDescriptor = new MetadataAttributeDescriptorImpl(); + MetadataAttributeImpl dataAttribute = new MetadataAttributeImpl(); + dataAttribute.setId("Multi"); + dataAttribute.setConceptIdentity(new IdentifiableArtefactReferenceImpl( + "CS1", "IMF", "1.0.0", StructureClassImpl.CONCEPT_SCHEME, "MULT" + )); + attributeDescriptor.getComponents().add(dataAttribute); + mdsd.setAttributeDescriptor(attributeDescriptor); + return mdsd; + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/MaintainableArtifactsTestUtils.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/MaintainableArtifactsTestUtils.java new file mode 100644 index 0000000..fbadbaa --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/MaintainableArtifactsTestUtils.java @@ -0,0 +1,1347 @@ +package com.epam.jsdmx.xml30.structure; + +import java.net.URI; +import java.net.URISyntaxException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import com.epam.jsdmx.infomodel.sdmx30.AfterPeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.AgencyImpl; +import com.epam.jsdmx.infomodel.sdmx30.AgencySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Annotation; +import com.epam.jsdmx.infomodel.sdmx30.AnnotationImpl; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseFacetImpl; +import com.epam.jsdmx.infomodel.sdmx30.BaseTextFormatRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.BeforePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.CascadeValue; +import com.epam.jsdmx.infomodel.sdmx30.CategorisationImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategoryImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtension; +import com.epam.jsdmx.infomodel.sdmx30.CodelistExtensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodingFormat; +import com.epam.jsdmx.infomodel.sdmx30.CodingFormatImpl; +import com.epam.jsdmx.infomodel.sdmx30.ComponentMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.ComponentValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.ComputationImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConstraintRoleType; +import com.epam.jsdmx.infomodel.sdmx30.Contact; +import com.epam.jsdmx.infomodel.sdmx30.ContactImpl; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionImpl; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionKeyImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataKeyImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySet; +import com.epam.jsdmx.infomodel.sdmx30.DataKeySetImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.DatePatternMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponentImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.EnumeratedRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.EpochMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.EpochPeriodType; +import com.epam.jsdmx.infomodel.sdmx30.ExclusiveCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.Facet; +import com.epam.jsdmx.infomodel.sdmx30.FacetType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueType; +import com.epam.jsdmx.infomodel.sdmx30.FacetValueTypeRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.FixedValueMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.FrequencyFormatMappingImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCode; +import com.epam.jsdmx.infomodel.sdmx30.GeoFeatureSetCodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeoGridCodelist; +import com.epam.jsdmx.infomodel.sdmx30.GeoGridCodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeographicCodelist; +import com.epam.jsdmx.infomodel.sdmx30.GeographicCodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.GridCode; +import com.epam.jsdmx.infomodel.sdmx30.GridCodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.GroupDimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.GroupRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchicalCodeImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyAssociation; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyAssociationImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableArtefactReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.IdentifiableObjectSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.InclusiveCodeSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.IsoConceptReferenceImpl; +import com.epam.jsdmx.infomodel.sdmx30.ItemMap; +import com.epam.jsdmx.infomodel.sdmx30.ItemMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.LevelImpl; +import com.epam.jsdmx.infomodel.sdmx30.ListReferenceValueRepresentationImpl; +import com.epam.jsdmx.infomodel.sdmx30.LocalisedMemberValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactImpl; +import com.epam.jsdmx.infomodel.sdmx30.MaintainableArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.MappedValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.MappingRoleType; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelection; +import com.epam.jsdmx.infomodel.sdmx30.MemberSelectionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeRefImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderScheme; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProvisionAgreement; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProvisionAgreementImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataTargetRegion; +import com.epam.jsdmx.infomodel.sdmx30.MetadataTargetRegionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.ObservationRelationshipImpl; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationSchemeMap; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationSchemeMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitImpl; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitScheme; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.infomodel.sdmx30.Process; +import com.epam.jsdmx.infomodel.sdmx30.ProcessArtefactImpl; +import com.epam.jsdmx.infomodel.sdmx30.ProcessImpl; +import com.epam.jsdmx.infomodel.sdmx30.ProcessStep; +import com.epam.jsdmx.infomodel.sdmx30.ProcessStepImpl; +import com.epam.jsdmx.infomodel.sdmx30.ProvisionAgreement; +import com.epam.jsdmx.infomodel.sdmx30.ProvisionAgreementImpl; +import com.epam.jsdmx.infomodel.sdmx30.RangePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendar; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendarImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReportingCategoryImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomy; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyMap; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.Representation; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMappingImpl; +import com.epam.jsdmx.infomodel.sdmx30.ResolvePeriod; +import com.epam.jsdmx.infomodel.sdmx30.SentinelValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureClassImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.TargetValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.TimeDimensionImpl; +import com.epam.jsdmx.infomodel.sdmx30.TimeRangePeriodImpl; +import com.epam.jsdmx.infomodel.sdmx30.TransitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.ValueItemImpl; +import com.epam.jsdmx.infomodel.sdmx30.ValueList; +import com.epam.jsdmx.infomodel.sdmx30.ValueListImpl; +import com.epam.jsdmx.infomodel.sdmx30.Version; +import com.epam.jsdmx.serializer.sdmx30.common.Header; + +public final class MaintainableArtifactsTestUtils { + + /** + * sets common fields for maintainable artefact + * + * @param artefact - artefact to set fields for + */ + public static void setMaintainableArtefact(MaintainableArtefactImpl artefact) { + artefact.setId("ARTEFACT"); + artefact.setVersion(Version.createFromString("1.2")); + artefact.setOrganizationId("IMF"); + artefact.setName(new InternationalString("Maintanable artefact")); + artefact.getName().add(Locale.CANADA_FRENCH.toLanguageTag(), "artefact"); + String date = "2022-07-17T10:11:16Z"; + + artefact.setValidTo(date); + artefact.setValidFrom(date); + artefact.setDescription(new InternationalString("Some artefact")); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("1"); + annotation.setText(new InternationalString("text")); + annotation.setType("type1"); + artefact.addAnnotation(annotation); + } + + /** + * @return Categorisation object + */ + public static CategorisationImpl buildCategorisation() { + CategorisationImpl categorisation = new CategorisationImpl(); + setMaintainableArtefact(categorisation); + IdentifiableArtefactReferenceImpl structureItemReference = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.CATEGORY, + "CAT_TARGET" + ); + + categorisation.setCategorizedBy(structureItemReference); + IdentifiableArtefactReferenceImpl structureReference = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.CATEGORISATION, + "CAT_SOURCE" + ); + categorisation.setCategorizedArtefact(structureReference); + return categorisation; + } + + /** + * @return CategoryScheme object + */ + public static CategorySchemeImpl buildCategoryScheme() { + CategorySchemeImpl categoryScheme = new CategorySchemeImpl(); + setMaintainableArtefact(categoryScheme); + categoryScheme.setPartial(true); + CategoryImpl category = new CategoryImpl(); + category.setDescription(new InternationalString("description")); + category.setId("Category-1"); + category.setName(new InternationalString("Category1")); + category.setDescription(new InternationalString("description category 1")); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot"); + category.setAnnotations(List.of(annotation)); + CategoryImpl category2 = new CategoryImpl(); + category2.setDescription(new InternationalString("description category2")); + category2.setId("Category-2"); + category2.setName(new InternationalString("Category2")); + AnnotationImpl annotation2 = new AnnotationImpl(); + annotation2.setId("Annot2"); + category2.setAnnotations(List.of(annotation, annotation2)); + CategoryImpl category3 = new CategoryImpl(); + category3.setDescription(new InternationalString("description category3")); + category3.setId("Category-3"); + category3.setName(new InternationalString("Category3")); + category.setHierarchy(List.of(category2, category3)); + + CategoryImpl category4 = new CategoryImpl(); + category4.setId("Category-4"); + category4.setName(new InternationalString("Category4")); + categoryScheme.setItems(List.of(category, category4)); + return categoryScheme; + } + + /** + * @return Codelist object + */ + public static CodelistImpl buildCodeList() { + CodelistImpl codelist = new CodelistImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(codelist); + codelist.setPartial(true); + codelist.setExtensions(getExtensions()); + fillCodes(codelist); + return codelist; + } + + private static void fillCodes(CodelistImpl codelist) { + CodeImpl code = new CodeImpl(); + code.setDescription(new InternationalString("code 1 desc")); + code.setId("CODE1"); + code.setName(new InternationalString("code 1")); + code.setParentId("CODE2"); + CodeImpl code2 = new CodeImpl(); + code2.setDescription(new InternationalString("code 2 desc")); + code2.setId("CODE2"); + code2.setName(new InternationalString("code 2")); + codelist.setItems(List.of(code, code2)); + } + + private static List getExtensions() { + CodelistExtensionImpl inclusiveCodeListExtension = fillInclusiveCodeListExtension(); + CodelistExtensionImpl exclusiveCodeListExtension = fillExclusiveCodeListExtension(); + return List.of(inclusiveCodeListExtension, exclusiveCodeListExtension); + } + + private static CodelistExtensionImpl fillExclusiveCodeListExtension() { + CodelistExtensionImpl codelistExtension = new CodelistExtensionImpl(); + ExclusiveCodeSelectionImpl exclusiveCodeSelection = new ExclusiveCodeSelectionImpl(); + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setCascadeValue(CascadeValue.FALSE); + memberValue.setValue("mem2"); + exclusiveCodeSelection.setMembers(List.of(memberValue)); + return fillCodeListExtension(codelistExtension, exclusiveCodeSelection); + } + + private static CodelistExtensionImpl fillInclusiveCodeListExtension() { + CodelistExtensionImpl codelistExtension = new CodelistExtensionImpl(); + InclusiveCodeSelectionImpl inclusiveCodeSelection = new InclusiveCodeSelectionImpl(); + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setCascadeValue(CascadeValue.TRUE); + memberValue.setValue("mem1"); + inclusiveCodeSelection.setMembers(List.of(memberValue)); + return fillCodeListExtension(codelistExtension, inclusiveCodeSelection); + } + + private static CodelistExtensionImpl fillCodeListExtension(CodelistExtensionImpl codelistExtension, BaseCodeSelectionImpl codeSelection) { + codelistExtension.setPrefix("PREF2"); + MaintainableArtefactReference maintainableReference = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1)"); + codelistExtension.setCodelist(maintainableReference); + codelistExtension.setCodeSelection(codeSelection); + return codelistExtension; + } + + /** + * @return ConceptScheme object + */ + public static ConceptSchemeImpl buildConceptScheme() { + ConceptSchemeImpl conceptScheme = new ConceptSchemeImpl(); + setMaintainableArtefact(conceptScheme); + ConceptImpl concept = new ConceptImpl(); + concept.setId("COUNTRY"); + concept.setName(new InternationalString("Country")); + IsoConceptReferenceImpl isoConceptReference = new IsoConceptReferenceImpl(); + isoConceptReference.setConceptId("Conn"); + isoConceptReference.setAgency("QHB"); + isoConceptReference.setSchemeId("Schema"); + concept.setIsoConceptReference(isoConceptReference); + concept.setCoreRepresentation(getRepresentation()); + conceptScheme.setItems(List.of(concept)); + conceptScheme.setPartial(true); + return conceptScheme; + } + + private static Representation getRepresentation() { + Set facetSet = new HashSet<>(); + BaseFacetImpl facet1 = new BaseFacetImpl(); + BaseFacetImpl facet2 = new BaseFacetImpl(); + BaseFacetImpl facet3 = new BaseFacetImpl(); + facet1.setValueType(FacetValueType.ALPHA); + SentinelValueImpl sentinelValue = new SentinelValueImpl(); + sentinelValue.setValue("val"); + sentinelValue.setName(new InternationalString("sent")); + sentinelValue.setDescription(new InternationalString("sentinel descr")); + facet2.setSentinelValues(List.of(sentinelValue)); + facet2.setType(FacetType.SENTINEL_VALUES); + facet2.setValueType(FacetValueType.ALPHA); + facet3.setType(FacetType.IS_MULTILINGUAL); + facet3.setValue("true"); + facetSet.addAll(List.of(facet1, facet2, facet3)); + return new BaseTextFormatRepresentationImpl(facetSet); + } + + /** + * @return DataConstraint object + */ + public static DataConstraintImpl buildDataConstraint() { + DataConstraintImpl dataConstraint = new DataConstraintImpl(); + setMaintainableArtefact(dataConstraint); + dataConstraint.setConstraintRoleType(ConstraintRoleType.ALLOWABLE_CONTENT); + + CubeRegionKeyImpl cubeRegionKey1 = new CubeRegionKeyImpl(); + cubeRegionKey1.setComponentId("CubeReg"); + cubeRegionKey1.setIncluded(true); + cubeRegionKey1.setRemovePrefix(true); + cubeRegionKey1.setValidFrom(Instant.parse("2020-04-12T12:00:00.000000Z")); + cubeRegionKey1.setValidTo(Instant.parse("2022-04-12T12:00:00.000000Z")); + cubeRegionKey1.setSelectionValues(List.of(getMemberValue())); + + CubeRegionImpl cubeRegion = new CubeRegionImpl(); + cubeRegion.setIncluded(true); + cubeRegion.setMemberSelections(getMemberSelections(true, false, "rangePeriod")); + cubeRegion.setCubeRegionKeys(List.of(cubeRegionKey1)); + cubeRegion.setAnnotations(getAnnotations()); + + dataConstraint.setCubeRegions(List.of(cubeRegion)); + dataConstraint.setReleaseCalendar(createReleaseCalendar()); + dataConstraint.setDataContentKeys(List.of(createDataKeySets())); + dataConstraint.setConstrainedArtefacts(List.of(buildProvisionAgreement().getDataProvider())); + + return dataConstraint; + } + + /** + * @return DataStructureDefinition object + */ + public static DataStructureDefinitionImpl buildDataStructureDefinition() { + DataStructureDefinitionImpl dataStructureDefinition = new DataStructureDefinitionImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(dataStructureDefinition); + MaintainableArtefactReference maintainableReference = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2)"); + dataStructureDefinition.setMetadataStructure(maintainableReference); + return dataStructureDefinition; + } + + /** + * @return MetadataStructureDefinition object + */ + public static MetadataStructureDefinitionImpl buildMetadataStructureDefinition() { + MetadataStructureDefinitionImpl metadataStructureDefinition = new MetadataStructureDefinitionImpl(); + setMaintainableArtefact(metadataStructureDefinition); + MetadataAttributeDescriptorImpl metadataAttributeDescriptor = new MetadataAttributeDescriptorImpl(); + metadataAttributeDescriptor.setId("MetadataAttributeDescriptor"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot-1"); + MetadataAttributeImpl metadataAttribute = getMetadataAttribute("meta-1", "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)"); + metadataAttribute.setHierarchy(List.of(getMetadataAttribute("meta-2", "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)"))); + metadataAttributeDescriptor.setComponents(List.of(metadataAttribute)); + metadataAttributeDescriptor.addAnnotation(annotation); + metadataStructureDefinition.setAttributeDescriptor(metadataAttributeDescriptor); + return metadataStructureDefinition; + } + + private static MetadataAttributeImpl getMetadataAttribute(String id, String reference) { + MetadataAttributeImpl metadataAttribute = new MetadataAttributeImpl(); + metadataAttribute.setId(id); + metadataAttribute.setMaxOccurs(20); + metadataAttribute.setMinOccurs(10); + metadataAttribute.setPresentational(true); + Representation representation = new EnumeratedRepresentationImpl( + new MaintainableArtefactReference(reference)); + metadataAttribute.setLocalRepresentation(representation); + metadataAttribute.setConceptIdentity( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DIM")); + return metadataAttribute; + } + + /** + * @return AttributeDescriptor + */ + public static AttributeDescriptorImpl fillAttributeDescriptor() { + AttributeDescriptorImpl attributeDescriptor = new AttributeDescriptorImpl(); + attributeDescriptor.setId("AttributeDescriptor"); + fillMetadata(attributeDescriptor); + fillComponents(attributeDescriptor); + return attributeDescriptor; + } + + + private static void fillComponents(AttributeDescriptorImpl attributeDescriptor) { + DataAttributeImpl dataAttribute = new DataAttributeImpl(); + dataAttribute.setId("DA1"); + dataAttribute.setMinOccurs(0); + dataAttribute.setMaxOccurs(1); + GroupRelationshipImpl groupRelationship = new GroupRelationshipImpl(); + groupRelationship.setGroupKey("GroupKey"); + dataAttribute.setAttributeRelationship(groupRelationship); + BaseFacetImpl baseFacet = new BaseFacetImpl(); + baseFacet.setValueType(FacetValueType.ALPHA_NUMERIC); + dataAttribute.setLocalRepresentation(new BaseTextFormatRepresentationImpl(Set.of(baseFacet))); + dataAttribute.setConceptIdentity(new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE")); + dataAttribute.setConceptRoles( + List.of( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE"), + new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE") + )); + MeasureRelationshipImpl measureRelationship = new MeasureRelationshipImpl(); + measureRelationship.setMeasures(List.of("MO")); + dataAttribute.setMeasureRelationship(measureRelationship); + attributeDescriptor.setComponents(List.of(dataAttribute)); + } + + private static void fillMetadata(AttributeDescriptorImpl attributeDescriptor) { + MetadataAttributeRefImpl attributeRef1 = new MetadataAttributeRefImpl(); + attributeRef1.setId("REFERENCE-1"); + attributeRef1.setMetadataRelationship(new ObservationRelationshipImpl()); + MetadataAttributeRefImpl attributeRef2 = new MetadataAttributeRefImpl(); + attributeRef2.setId("REFERENCE-2"); + DimensionRelationshipImpl dimensionRelationship = new DimensionRelationshipImpl(); + dimensionRelationship.setDimensions(List.of("dim1", "dim2")); + attributeRef2.setMetadataRelationship(dimensionRelationship); + MetadataAttributeRefImpl attributeRef3 = new MetadataAttributeRefImpl(); + attributeRef3.setId("REFERENCE-3"); + attributeRef3.setMetadataRelationship(null); + attributeDescriptor.setMetadataAttributes(List.of(attributeRef1, attributeRef2, attributeRef3)); + } + + /** + * @return List + */ + public static List fillListGroupDimensionDescriptor() { + GroupDimensionDescriptorImpl groupDimensionDescriptor1 = new GroupDimensionDescriptorImpl(); + AnnotationImpl annotation1 = new AnnotationImpl(); + annotation1.setId("id1"); + annotation1.setValue("val"); + AnnotationImpl annotation2 = new AnnotationImpl(); + annotation2.setId("id2"); + annotation2.setValue("val"); + groupDimensionDescriptor1.setId("GroupDimensionDescriptor1"); + groupDimensionDescriptor1.setAnnotations(List.of(annotation1, annotation2)); + groupDimensionDescriptor1.setDimensions(List.of("DIM1", "TIME_PERIOD")); + + GroupDimensionDescriptorImpl groupDimensionDescriptor2 = new GroupDimensionDescriptorImpl(); + groupDimensionDescriptor2.setId("GroupDimensionDescriptor2"); + groupDimensionDescriptor2.setDimensions(List.of("DIM1")); + + return List.of(groupDimensionDescriptor1, groupDimensionDescriptor2); + } + + /** + * @return DimensionDescriptor + */ + public static DimensionDescriptorImpl fillDimensionDescriptor() { + DimensionDescriptorImpl dimensionDescriptor = new DimensionDescriptorImpl(); + dimensionDescriptor.setId("DimensionDescriptor"); + fillDimensionComponents(dimensionDescriptor); + return dimensionDescriptor; + } + + private static void fillDimensionComponents(DimensionDescriptorImpl dimensionDescriptor) { + DimensionImpl dimensionComponent = new DimensionImpl(); + dimensionComponent.setOrder(1); + dimensionComponent.setId("DIM1"); + dimensionComponent.setConceptRoles(List.of(new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE"))); + EnumeratedRepresentationImpl enumeratedRepresentation = new EnumeratedRepresentationImpl( + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0)")); + dimensionComponent.setLocalRepresentation(enumeratedRepresentation); + dimensionComponent.setConceptIdentity( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE")); + DimensionComponentImpl dimensionTimeComponent = new TimeDimensionImpl(); + dimensionTimeComponent.setId("TIME_PERIOD"); + dimensionTimeComponent.setOrder(2); + dimensionTimeComponent.setConceptIdentity( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE")); + BaseFacetImpl baseFacet = new BaseFacetImpl(); + baseFacet.setValueType(FacetValueType.BASIC_TIME_PERIOD); + dimensionTimeComponent.setLocalRepresentation(new BaseTextFormatRepresentationImpl(Set.of(baseFacet))); + dimensionDescriptor.setComponents(List.of(dimensionComponent, dimensionTimeComponent)); + } + + /** + * @return MeasureDescriptor + */ + public static MeasureDescriptorImpl fillMeasureDescriptor() { + MeasureDescriptorImpl measureDescriptor = new MeasureDescriptorImpl(); + measureDescriptor.setId("MeasureDescriptor"); + fillMeasureComponents(measureDescriptor); + return measureDescriptor; + } + + private static void fillMeasureComponents(MeasureDescriptorImpl measureDescriptor) { + MeasureImpl measure = new MeasureImpl(); + measure.setId("MES1"); + measure.setConceptIdentity(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE")); + measure.setConceptRoles( + List.of( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE"), + new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE") + )); + BaseFacetImpl baseFacet = new BaseFacetImpl(); + baseFacet.setValueType(FacetValueType.BASIC_TIME_PERIOD); + measure.setLocalRepresentation(new BaseTextFormatRepresentationImpl(Set.of(baseFacet))); + measureDescriptor.setComponents(List.of(measure)); + } + + /** + * @return Hierarchy object + */ + public static HierarchyImpl buildHierarchy() { + HierarchyImpl hierarchy = new HierarchyImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(hierarchy); + hierarchy.setHasFormalLevels(true); + HierarchicalCodeImpl code = new HierarchicalCodeImpl(); + code.setId("id"); + code.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1")); + code.setLevelId("Lev1"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("id"); + code.setAnnotations(List.of(annotation)); + String dateStr = "2022-07-17T10:11:16.345Z"; + code.setValidTo(Instant.parse(dateStr)); + code.setValidFrom(Instant.parse(dateStr)); + HierarchicalCodeImpl code2 = new HierarchicalCodeImpl(); + code2.setId("hi-2"); + code2.setLevelId("Lev2"); + code2.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL2")); + code2.setValidTo(Instant.parse(dateStr)); + code2.setValidFrom(Instant.parse(dateStr)); + hierarchy.setCodes(List.of(code, code2)); + LevelImpl level = new LevelImpl(); + level.setDescription(new InternationalString("hierarchy desc")); + level.setName(new InternationalString("hierarchy name")); + level.setId("levId"); + level.setCodeFormat(List.of(fillListOfCodingFormats().get(0))); + hierarchy.setLevel(level); + return hierarchy; + } + + public static HierarchyImpl buildHierarchyWithInnerHierarchy() { + HierarchyImpl hierarchy = new HierarchyImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(hierarchy); + hierarchy.setHasFormalLevels(true); + HierarchicalCodeImpl code = new HierarchicalCodeImpl(); + code.setId("id"); + code.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1")); + code.setLevelId("Lev1"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("id"); + code.setAnnotations(List.of(annotation)); + String dateStr = "2022-07-17T10:11:16.345Z"; + code.setValidTo(Instant.parse(dateStr)); + code.setValidFrom(Instant.parse(dateStr)); + HierarchicalCodeImpl hierarchicalCode = new HierarchicalCodeImpl(); + hierarchicalCode.setCode(new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1")); + hierarchicalCode.setId("1"); + hierarchicalCode.setValidTo(Instant.parse(dateStr)); + hierarchicalCode.setValidFrom(Instant.parse(dateStr)); + code.setHierarchicalCodes(List.of(hierarchicalCode)); + hierarchy.setCodes(List.of(code)); + LevelImpl level = new LevelImpl(); + level.setDescription(new InternationalString("hierarchy desc")); + level.setName(new InternationalString("hierarchy name")); + level.setId("levId"); + level.setCodeFormat(List.of(fillListOfCodingFormats().get(0))); + hierarchy.setLevel(level); + LevelImpl levelUn = new LevelImpl(); + levelUn.setId("levUn"); + levelUn.setName(new InternationalString("underLevel")); + level.setChild(levelUn); + return hierarchy; + } + + private static List fillListOfCodingFormats() { + List codingFormatList = new ArrayList<>(); + codingFormatList.add(addCodingFormat(FacetType.INTERVAL, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.IS_SEQUENCE, String.valueOf(true))); + codingFormatList.add(addCodingFormat(FacetType.MAX_LENGTH, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.MIN_LENGTH, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.MAX_VALUE, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.MIN_VALUE, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.PATTERN, "a")); + codingFormatList.add(addCodingFormat(FacetType.START_VALUE, String.valueOf(1))); + codingFormatList.add(addCodingFormat(FacetType.END_VALUE, String.valueOf(1))); + + CodingFormatImpl codingFormat = new CodingFormatImpl(); + codingFormat.setCodingFormat(new BaseFacetImpl(FacetValueType.fromValue("Alpha"))); + codingFormatList.add(codingFormat); + return codingFormatList; + } + + private static CodingFormat addCodingFormat(FacetType facetType, String value) { + CodingFormatImpl codingFormat = new CodingFormatImpl(); + BaseFacetImpl baseFacet = new BaseFacetImpl(); + baseFacet.setType(facetType); + baseFacet.setValue(value); + codingFormat.setCodingFormat(baseFacet); + return codingFormat; + } + + /** + * @return Metadataflow object + */ + public static MetadataflowImpl buildMetadataFlow() { + MetadataflowImpl metadataflow = new MetadataflowImpl(); + setMaintainableArtefact(metadataflow); + metadataflow.setStructure(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=IMF:METADATA(1.0.0)")); + IdentifiableObjectSelectionImpl objectSelection = new IdentifiableObjectSelectionImpl(); + MaintainableArtefactReference maintainableArtefactReference = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)"); + + MaintainableArtefactReference maintainableArtefactReference2 = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.3)"); + objectSelection.setResolvesTo(List.of(maintainableArtefactReference, maintainableArtefactReference2)); + metadataflow.setSelections(List.of(objectSelection)); + return metadataflow; + } + + /** + * @return Dataflow object + */ + public static DataflowImpl buildDataFlow() { + DataflowImpl dataflow = new DataflowImpl(); + dataflow.setId("DF"); + dataflow.setStructure(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2)")); + setMaintainableArtefact(dataflow); + return dataflow; + } + + /** + * @return AgencyScheme + */ + + public static AgencySchemeImpl buildAgencyScheme() { + AgencySchemeImpl agencyScheme = new AgencySchemeImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(agencyScheme); + agencyScheme.setId("AGENCIES"); + agencyScheme.setOrganizationId("SDMX"); + agencyScheme.setVersion(Version.createFromString("1.0")); + AgencyImpl agency1 = createAgency("AG-1"); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot"); + agency1.setAnnotations(List.of(annotation)); + AgencyImpl agency2 = createAgency("AG-2"); + + + agencyScheme.setItems(List.of(agency1, agency2)); + return agencyScheme; + } + + private static AgencyImpl createAgency(String id) { + AgencyImpl agency1 = new AgencyImpl(); + agency1.setId(id); + agency1.setName(new InternationalString("Agency")); + agency1.setDescription(new InternationalString("Agency")); + + List contacts = getContacts(); + + agency1.setContacts(contacts); + return agency1; + } + + private static List getContacts() { + ContactImpl contact1 = new ContactImpl(); + contact1.setName("AG_1"); + contact1.setTelephone("9458673082"); + contact1.setFax("somedatafax"); + contact1.setEmail("test@email.com"); + contact1.setOrganizationUnit("IT"); + Map resp = new HashMap<>(); + resp.put("en", "writing"); + resp.put("fr", "ecrire"); + contact1.setResponsibility(new InternationalString(resp)); + contact1.setX400("X400"); + + ContactImpl contact2 = new ContactImpl(); + contact2.setName("AG_2"); + contact2.setTelephone("9458673082"); + contact2.setFax("somedatafax2"); + contact2.setEmail("test@email.com"); + contact2.setOrganizationUnit("IT"); + contact2.setResponsibility(new InternationalString(resp)); + contact2.setX400("X400"); + return List.of(contact1, contact2); + } + + /** + * @return CategorySchemeMap + */ + + public static CategorySchemeMapImpl buildCategorySchemeMap() { + CategorySchemeMapImpl categorySchemeMap = new CategorySchemeMapImpl(); + setMaintainableArtefact(categorySchemeMap); + categorySchemeMap.setSource(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:CatScheme(1.0)")); + categorySchemeMap.setTarget(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:CatScheme(1.1)")); + ItemMap itemMap = createItemMap("IM-1", "S-1"); + ItemMap itemMap2 = createItemMap("IM-2", "S-2"); + categorySchemeMap.setItemMaps(List.of(itemMap, itemMap2)); + return categorySchemeMap; + } + + private static ItemMap createItemMap(String target, String source) { + ItemMapImpl itemMap = new ItemMapImpl(); + itemMap.setTarget(target); + itemMap.setSource(source); + itemMap.setValidTo(Instant.parse("2022-07-17T00:00:00Z")); + itemMap.setValidFrom(Instant.parse("2022-07-17T00:00:00Z")); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Ann"); + itemMap.setAnnotations(List.of(annotation)); + return itemMap; + } + + /** + * @return ConceptSchemeMap + */ + + public static ConceptSchemeMapImpl buildConceptSchemeMap() { + ConceptSchemeMapImpl conceptSchemeMap = new ConceptSchemeMapImpl(); + setMaintainableArtefact(conceptSchemeMap); + conceptSchemeMap.setSource(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ConScheme(1.0)")); + conceptSchemeMap.setTarget(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ConScheme(1.1)")); + ItemMap itemMap = createItemMap("IM-1", "S-1"); + ItemMap itemMap2 = createItemMap("IM-2", "S-2"); + conceptSchemeMap.setItemMaps(List.of(itemMap, itemMap2)); + return conceptSchemeMap; + } + + /** + * @return DataConsumerSchemeImpl + */ + public static DataConsumerSchemeImpl buildDataConsumerScheme() { + DataConsumerSchemeImpl dataConsumerScheme = new DataConsumerSchemeImpl(); + setMaintainableArtefact(dataConsumerScheme); + dataConsumerScheme.setVersion(Version.createFromString("1.0")); + dataConsumerScheme.setId("DATA_CONSUMERS"); + DataConsumerImpl dataConsumer = new DataConsumerImpl(); + dataConsumer.setId("DC"); + dataConsumer.setName(new InternationalString("Data Consumer")); + dataConsumer.setDescription(new InternationalString("Data Consumer description")); + dataConsumer.setContacts(getContacts()); + dataConsumerScheme.setItems(List.of(dataConsumer)); + return dataConsumerScheme; + } + + /** + * @return RepresentationMap object + */ + public static RepresentationMapImpl buildRepresentationMap() { + RepresentationMapImpl representationMap = new RepresentationMapImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(representationMap); + fillSource(representationMap, "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_SOURCE(1.0)"); + fillTarget(representationMap, "urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_TARGET(1.0)"); + fillRepresentationMappings(representationMap, "2022-07-17T00:00:00.000Z"); + return representationMap; + } + + public static void fillTarget(RepresentationMapImpl representationMap, String referenceUrn) { + ListReferenceValueRepresentationImpl valueRepresentation = new ListReferenceValueRepresentationImpl(); + valueRepresentation.setReference(new MaintainableArtefactReference(referenceUrn)); + representationMap.setTarget(List.of(valueRepresentation)); + } + + public static void fillSource(RepresentationMapImpl representationMap, String referenceUrn) { + ListReferenceValueRepresentationImpl valueRepresentation = new ListReferenceValueRepresentationImpl(); + valueRepresentation.setReference(new MaintainableArtefactReference(referenceUrn)); + FacetValueTypeRepresentationImpl valueRepresentation2 = new FacetValueTypeRepresentationImpl(); + valueRepresentation2.setType(FacetValueType.DATE_TIME); + representationMap.setSource(List.of(valueRepresentation, valueRepresentation2)); + } + + public static void fillRepresentationMappings(RepresentationMapImpl representationMap, String date) { + RepresentationMappingImpl representationMapping = new RepresentationMappingImpl(); + Instant instant = Instant.parse(date); + representationMapping.setValidFrom(instant); + representationMapping.setValidTo(instant); + fillSourceValues(representationMapping); + fillTargetValues(representationMapping); + representationMap.setRepresentationMappings(List.of(representationMapping)); + } + + static void fillTargetValues(RepresentationMappingImpl representationMapping) { + TargetValueImpl targetValue1 = new TargetValueImpl(); + targetValue1.setValue("targetValue1"); + TargetValueImpl targetValue2 = new TargetValueImpl(); + targetValue2.setValue("targetValue2"); + representationMapping.setTargetValues(List.of(targetValue1, targetValue2)); + } + + static void fillSourceValues(RepresentationMappingImpl representationMapping) { + MappedValueImpl mappedValue = new MappedValueImpl(); + mappedValue.setValue("mappedValue"); + mappedValue.setRegEx(true); + mappedValue.setStartIndex(0); + mappedValue.setEndIndex(10); + representationMapping.setSourceValues(List.of(mappedValue)); + } + + /** + * @return StructureMap object + */ + public static StructureMapImpl buildStructureMap() { + StructureMapImpl structureMap = new StructureMapImpl(); + MaintainableArtifactsTestUtils.setMaintainableArtefact(structureMap); + structureMap.setSource(new MaintainableArtefactReference("DataFSource", "EPM", "3.0", StructureClassImpl.DATAFLOW)); + structureMap.setTarget(new MaintainableArtefactReference("DataFTarget", "EPM", "3.0", StructureClassImpl.DATAFLOW)); + fillEpochMap(structureMap); + fillFixedValueMap(structureMap); + fillComponentMap(structureMap); + fillDatePattern(structureMap); + return structureMap; + } + + static void fillDatePattern(StructureMapImpl structureMap) { + DatePatternMapImpl datePatternMap = new DatePatternMapImpl(); + datePatternMap.setLocale("EN"); + datePatternMap.setSourcePattern("SOURCE"); + datePatternMap.setId("DP1"); + datePatternMap.setResolvePeriod(ResolvePeriod.MID_PERIOD); + FrequencyFormatMappingImpl frequencyFormatMapping1 = getFrequencyFormatMapping("CODE_1", "2022-11", "FR1"); + FrequencyFormatMappingImpl frequencyFormatMapping2 = getFrequencyFormatMapping("CODE_2", "2022-11", "FR2"); + datePatternMap.setMappedFrequencies(List.of(frequencyFormatMapping1, frequencyFormatMapping2)); + datePatternMap.setFrequencyDimension("Frequency_dim"); + structureMap.setDatePatternMaps(List.of(datePatternMap)); + } + + private static FrequencyFormatMappingImpl getFrequencyFormatMapping(String freqCode, String datePattern, String id) { + FrequencyFormatMappingImpl frequencyFormatMapping = new FrequencyFormatMappingImpl(); + frequencyFormatMapping.setFrequencyCode(freqCode); + frequencyFormatMapping.setDatePattern(datePattern); + frequencyFormatMapping.setId(id); + return frequencyFormatMapping; + } + + static void fillComponentMap(StructureMapImpl structureMap) { + + ComponentMapImpl componentMapDP = new ComponentMapImpl(); + componentMapDP.setSource(List.of("CompMapEpochS")); + componentMapDP.setTarget(List.of("CompMapEpochT")); + IdentifiableArtefactReferenceImpl reference = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.EPOCH_MAP, + "EPOCH1" + ); + componentMapDP.setRepresentationMap(reference); + + + ComponentMapImpl componentMapEpoch = new ComponentMapImpl(); + componentMapEpoch.setSource(List.of("CompMapDPS")); + componentMapEpoch.setTarget(List.of("CompMapDPT")); + IdentifiableArtefactReferenceImpl reference2 = new IdentifiableArtefactReferenceImpl( + "ARTEFACT", + "IMF", + "1.2", + StructureClassImpl.DATE_PATTERN_MAP, + "DP1" + ); + componentMapEpoch.setRepresentationMap(reference2); + + ComponentMapImpl componentMaRep = new ComponentMapImpl(); + componentMaRep.setSource(List.of("CompMapRepS")); + componentMaRep.setTarget(List.of("CompMapRepT")); + MaintainableArtefactReference reference3 = new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2)"); + componentMaRep.setRepresentationMap(reference3); + + structureMap.setComponentMaps(List.of(componentMapEpoch, componentMapDP, componentMaRep)); + } + + static void fillFixedValueMap(StructureMapImpl structureMap) { + FixedValueMapImpl fixedValueMap = new FixedValueMapImpl(); + fixedValueMap.setRole(MappingRoleType.TARGET); + fixedValueMap.setComponent("STRUC_ID"); + fixedValueMap.setValue("value"); + structureMap.setFixedComponentMaps(List.of(fixedValueMap)); + } + + static void fillEpochMap(StructureMapImpl structureMap) { + EpochMapImpl epochMap = new EpochMapImpl(); + epochMap.setEpochPeriod(EpochPeriodType.MICROSECOND); + Instant instant = Instant.parse("2022-07-17T10:11:16Z"); + epochMap.setBasePeriod(instant); + epochMap.setId("EPOCH1"); + epochMap.setResolvePeriod(ResolvePeriod.MID_PERIOD); + FrequencyFormatMappingImpl frequencyFormatMapping3 = getFrequencyFormatMapping("CODE_3", "2022-11", "FR3"); + epochMap.setMappedFrequencies(List.of(frequencyFormatMapping3)); + epochMap.setFrequencyDimension("Frequency_dim"); + structureMap.setEpochMaps(List.of(epochMap)); + } + + /** + * @return Header + */ + public static Header buildHeader() throws URISyntaxException { + Header header = new Header(); + header.setId("IDREF8124"); + URI uri = new URI("https://raw.githubusercontent.com/sdmx-twg/sdmx-json/master/metadata-message/tools/schemas/2.0.0/sdmx-json-metadata-schema.json"); + header.setSchema(uri); + Instant instant = Instant.parse("2021-11-02T09:47:41Z"); + header.setPrepared(instant); + Party sender = new Party(); + sender.setId("unknown"); + header.setSender(sender); + Locale locale = new Locale("en"); + header.setContentLanguages(List.of(locale)); + return header; + } + + public static DataProviderSchemeImpl buildDataProviderScheme() { + + DataProviderSchemeImpl dataProviderScheme = new DataProviderSchemeImpl(); + setMaintainableArtefact(dataProviderScheme); + dataProviderScheme.setVersion(Version.createFromString("1.0")); + dataProviderScheme.setId("DATA_PROVIDERS"); + dataProviderScheme.setPartial(true); + + DataProviderImpl dataProvider = new DataProviderImpl(); + dataProvider.setContacts(getContacts()); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Ann"); + annotation.setValue("Val"); + dataProvider.setAnnotations(List.of(annotation)); + dataProvider.setId("Prov"); + dataProvider.setName(new InternationalString("D_P")); + + dataProviderScheme.setItems(List.of(dataProvider)); + return dataProviderScheme; + } + + public static MetadataProviderScheme buildMetadataProviderScheme() { + + MetadataProviderSchemeImpl metadataProviderScheme = new MetadataProviderSchemeImpl(); + setMaintainableArtefact(metadataProviderScheme); + metadataProviderScheme.setVersion(Version.createFromString("1.0")); + metadataProviderScheme.setId("METADATA_PROVIDERS"); + metadataProviderScheme.setPartial(true); + + MetadataProviderImpl metadataProvider = new MetadataProviderImpl(); + metadataProvider.setContacts(getContacts()); + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Ann"); + annotation.setValue("Val"); + metadataProvider.setAnnotations(List.of(annotation)); + metadataProvider.setId("Prov"); + metadataProvider.setName(new InternationalString("MD_P")); + + metadataProviderScheme.setItems(List.of(metadataProvider)); + return metadataProviderScheme; + } + + public static HierarchyAssociation buildHierarchyAssociation() { + HierarchyAssociationImpl hierarchyAssociation = new HierarchyAssociationImpl(); + setMaintainableArtefact(hierarchyAssociation); + hierarchyAssociation.setLinkedHierarchy(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.codelist.Hierarchy=IMF:ARTEFACT(1.2)")); + hierarchyAssociation.setContextObject(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2)")); + hierarchyAssociation.setLinkedObject(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.3)")); + return hierarchyAssociation; + } + + public static MetadataConstraintImpl buildMetadataConstraint(boolean isJson) { + MetadataConstraintImpl metadataConstraint = new MetadataConstraintImpl(); + setMaintainableArtefact(metadataConstraint); + metadataConstraint.setConstraintRoleType(ConstraintRoleType.ALLOWABLE_CONTENT); + metadataConstraint.setMetadataTargetRegions(createMetadataTargetRegions(isJson)); + metadataConstraint.setReleaseCalendar(createReleaseCalendar()); + metadataConstraint.setConstrainedArtefacts(createMetadataConstrainedArtefacts()); + return metadataConstraint; + } + + private static List createMetadataConstrainedArtefacts() { + IdentifiableArtefactReferenceImpl maintainableArtefactReference = new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.base.MetadataProvider=IMF:METADATA_PROVIDERS(1.0).PR"); + return List.of(maintainableArtefactReference); + } + + private static List createMetadataTargetRegions(boolean isJson) { + MetadataTargetRegionImpl metadataTargetRegion = new MetadataTargetRegionImpl(); + metadataTargetRegion.setIncluded(true); + metadataTargetRegion.setValidTo(Instant.parse("2022-07-17T10:11:16Z")); + metadataTargetRegion.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + List memberSelectionList = getMemberSelections(false, isJson, "beforePeriod"); + metadataTargetRegion.setMemberSelections(memberSelectionList); + + return List.of(metadataTargetRegion); + } + + private static List getMemberSelections(boolean isSimple, boolean isJson, String timePeriod) { + MemberSelectionImpl memberSelection = new MemberSelectionImpl(); + memberSelection.setIncluded(false); + memberSelection.setRemovePrefix(true); + memberSelection.setComponentId("MS"); + + MemberValueImpl memberValue; + if (isSimple) { + memberValue = getMemberValueSimple(); + } else { + memberValue = getMemberValue(); + } + + LocalisedMemberValueImpl localisedMemberValue = new LocalisedMemberValueImpl(); + localisedMemberValue.setValue("local"); + localisedMemberValue.setLocale("en"); + + memberSelection.setSelectionValues(List.of(memberValue, localisedMemberValue)); + + MemberSelectionImpl memberSelection2 = new MemberSelectionImpl(); + memberSelection2.setIncluded(false); + memberSelection2.setRemovePrefix(true); + memberSelection2.setComponentId("MS2"); + BeforePeriodImpl beforePeriod = new BeforePeriodImpl(); + beforePeriod.setInclusive(true); + beforePeriod.setPeriod("2023"); + if (!isJson) { + beforePeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + beforePeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + } + + AfterPeriodImpl afterPeriod = new AfterPeriodImpl(); + afterPeriod.setInclusive(false); + afterPeriod.setPeriod("2028"); + afterPeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + afterPeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + + RangePeriodImpl rangePeriod = new RangePeriodImpl(); + TimeRangePeriodImpl timeRangePeriod = new TimeRangePeriodImpl(); + timeRangePeriod.setInclusive(true); + timeRangePeriod.setPeriod("2022"); + timeRangePeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + timeRangePeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + + rangePeriod.setStartPeriod(timeRangePeriod); + timeRangePeriod.setInclusive(false); + rangePeriod.setEndPeriod(timeRangePeriod); + rangePeriod.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + rangePeriod.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + + if (timePeriod.equals("beforePeriod")) { + memberSelection2.setSelectionValues(List.of(beforePeriod)); + } else if (timePeriod.equals("afterPeriod")) { + memberSelection2.setSelectionValues(List.of(afterPeriod)); + } else { + memberSelection2.setSelectionValues(List.of(rangePeriod)); + } + + return List.of(memberSelection, memberSelection2); + } + + private static MemberValueImpl getMemberValue() { + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setValue("MEM"); + memberValue.setCascadeValue(CascadeValue.EXCLUDE_ROOT); + memberValue.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + memberValue.setValidTo(Instant.parse("2022-09-17T10:11:16Z")); + return memberValue; + } + + private static MemberValueImpl getMemberValueSimple() { + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setValue("MEM"); + return memberValue; + } + + private static ReleaseCalendar createReleaseCalendar() { + ReleaseCalendarImpl releaseCalendar = new ReleaseCalendarImpl(); + releaseCalendar.setOffset("Offset"); + releaseCalendar.setTolerance("Tolerance"); + releaseCalendar.setPeriodicity("Periodicity"); + return releaseCalendar; + } + + private static DataKeySet createDataKeySets() { + DataKeySetImpl dataKeySet = new DataKeySetImpl(); + dataKeySet.setIncluded(true); + DataKeyImpl dataKey = new DataKeyImpl(); + dataKey.setIncluded(true); + ComponentValueImpl componentValue = new ComponentValueImpl(); + componentValue.setIncluded(true); + componentValue.setComponentId("C1"); + componentValue.setRemovePrefix(true); + componentValue.setValue("Value"); + dataKey.setKeyValues(List.of(componentValue)); + dataKey.setMemberSelections(getMemberSelections(true, false, "afterPeriod")); + dataKey.setValidFrom(Instant.parse("2022-07-17T10:11:16Z")); + dataKey.setValidTo(Instant.parse("2022-07-17T10:11:16Z")); + dataKeySet.setKeys(List.of(dataKey)); + + return dataKeySet; + } + + public static MetadataProvisionAgreement buildMetadataProvisionAgreement() { + MetadataProvisionAgreementImpl metadataProvisionAgreement = new MetadataProvisionAgreementImpl(); + setMaintainableArtefact(metadataProvisionAgreement); + metadataProvisionAgreement.setControlledStructureUsage(new MaintainableArtefactReference( + "urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=IMF:ARTEFACT(1.2)")); + metadataProvisionAgreement.setMetadataProvider(new IdentifiableArtefactReferenceImpl( + "urn:sdmx:org.sdmx.infomodel.base.MetadataProvider=IMF:METADATA_PROVIDERS(1.0).PR")); + return metadataProvisionAgreement; + } + + public static OrganisationSchemeMap buildOrganisationSchemeMap() { + OrganisationSchemeMapImpl organisationSchemeMap = new OrganisationSchemeMapImpl(); + setMaintainableArtefact(organisationSchemeMap); + organisationSchemeMap.setSource(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.base.AgencyScheme=SDMX:AGENCIES(1.0)")); + organisationSchemeMap.setTarget(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.base.AgencyScheme=SDMX:AGENCIES(1.0)")); + ItemMap itemMap = createItemMap("IM-1", "S-1"); + ItemMap itemMap2 = createItemMap("IM-2", "S-2"); + organisationSchemeMap.setItemMaps(List.of(itemMap, itemMap2)); + return organisationSchemeMap; + } + + public static Process buildProcess() { + ProcessImpl process = new ProcessImpl(); + setMaintainableArtefact(process); + List processSteps = new ArrayList<>(); + ProcessStepImpl processStep = new ProcessStepImpl(); + processStep.setId("ProcStep"); + processStep.setName(new InternationalString("ProcessStep")); + processStep.setDescription(new InternationalString("ProcessStep description")); + + ProcessArtefactImpl processArtefact = new ProcessArtefactImpl(); + processArtefact.setLocalId("Loc"); + processArtefact.setArtefact(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.process.ProcessStep=IMF:Artefact(1.0)")); + processArtefact.setAnnotations(getAnnotations()); + processStep.setInputs(List.of(processArtefact)); + processStep.setOutputs(List.of(processArtefact)); + + TransitionImpl transition = new TransitionImpl(); + transition.setId("Trans"); + transition.setLocalId("Loc"); + transition.setTargetProcessStep("ST"); + transition.setCondition(new InternationalString("Doo")); + processStep.setTransitions(List.of(transition)); + + ComputationImpl computation = new ComputationImpl(); + computation.setLocalId("LocId"); + computation.setSoftwareLanguage("SoftwareLanguage"); + computation.setSoftwarePackage("SoftwarePackage"); + computation.setSoftwareVersion("SoftwareVersion"); + computation.setAnnotations(getAnnotations()); + computation.setDescription(new InternationalString("Computation Description")); + processStep.setComputation(computation); + + ProcessStepImpl processStepChild = new ProcessStepImpl(); + processStepChild.setId("ProcessChild"); + processStepChild.setAnnotations(getAnnotations()); + processStepChild.setName(new InternationalString("ProcessStepChild")); + processStep.setChildren(List.of(processStepChild)); + processStep.setAnnotations(getAnnotations()); + processSteps.add(processStep); + process.setSteps(processSteps); + + return process; + } + + + public static ProvisionAgreement buildProvisionAgreement() { + ProvisionAgreementImpl provisionAgreement = new ProvisionAgreementImpl(); + setMaintainableArtefact(provisionAgreement); + provisionAgreement.setControlledStructureUsage( + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=IMF:ARTEFACT(1.2)")); + provisionAgreement.setDataProvider( + new IdentifiableArtefactReferenceImpl("urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP")); + return provisionAgreement; + } + + public static ReportingTaxonomy buildReportingTaxonomy() { + ReportingTaxonomyImpl reportingTaxonomy = new ReportingTaxonomyImpl(); + setMaintainableArtefact(reportingTaxonomy); + ReportingCategoryImpl reportingCategory1 = new ReportingCategoryImpl(); + reportingCategory1.setId("RC-1"); + reportingCategory1.setName(new InternationalString("ReportingCat")); + reportingCategory1.setDescription(new InternationalString("ReportingCat description")); + reportingCategory1.setAnnotations(getAnnotations()); + reportingCategory1.setFlows(List.of( + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataS2(3.0)"), + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataS1(3.0)") + + )); + ReportingCategoryImpl reportingCategory2 = new ReportingCategoryImpl(); + reportingCategory2.setId("RC-2"); + reportingCategory2.setName(new InternationalString("ReportingCat2")); + reportingCategory2.setDescription(new InternationalString("ReportingCat2 description")); + reportingCategory2.setAnnotations(getAnnotations()); + reportingCategory2.setStructures(List.of( + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=EPM:DataS2(3.0)"), + new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=EPM:DataS1(3.0)") + )); + reportingCategory1.setHierarchy(List.of(reportingCategory2)); + reportingTaxonomy.setItems(List.of(reportingCategory1)); + return reportingTaxonomy; + } + + public static ReportingTaxonomyMap buildReportingTaxonomyMap() { + ReportingTaxonomyMapImpl reportingTaxonomyMap = new ReportingTaxonomyMapImpl(); + setMaintainableArtefact(reportingTaxonomyMap); + reportingTaxonomyMap.setSource(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.categoryscheme.ReportingTaxonomy=SDMX:REP_SOURCE(1.0)")); + reportingTaxonomyMap.setTarget(new MaintainableArtefactReference("urn:sdmx:org.sdmx.infomodel.categoryscheme.ReportingTaxonomy=SDMX:REP_TARGET(1.0)")); + ItemMap itemMap = createItemMap("IM-1", "S-1"); + ItemMap itemMap2 = createItemMap("IM-2", "S-2"); + reportingTaxonomyMap.setItemMaps(List.of(itemMap, itemMap2)); + return reportingTaxonomyMap; + } + + public static ValueList buildValueList() { + ValueListImpl valueList = new ValueListImpl(); + setMaintainableArtefact(valueList); + ValueItemImpl valueItem = new ValueItemImpl(); + valueItem.setId("VAL-1"); + Map names = new HashMap<>(); + names.put("en", "value"); + names.put("fr", "val"); + Map descriptions = new HashMap<>(); + descriptions.put("en", "it is value"); + descriptions.put("fr", "c'est val"); + valueItem.setName(new InternationalString(names)); + valueItem.setDescription(new InternationalString(descriptions)); + valueItem.setAnnotations(getAnnotations()); + + ValueItemImpl valueItem2 = new ValueItemImpl(); + valueItem2.setId("VAL-2"); + valueItem2.setName(new InternationalString("smth")); + valueItem2.setDescription(new InternationalString("smth description")); + valueItem2.setAnnotations(getAnnotations()); + valueList.setItems(List.of(valueItem, valueItem2)); + return valueList; + } + + public static GeographicCodelist buildGeographicCodelist() { + GeographicCodelistImpl geographicCodelist = new GeographicCodelistImpl(); + setMaintainableArtefact(geographicCodelist); + geographicCodelist.setItems(getGeoFeatureSetCodes()); + geographicCodelist.setExtensions(getExtensions()); + geographicCodelist.setPartial(true); + return geographicCodelist; + } + + private static List getGeoFeatureSetCodes() { + GeoFeatureSetCodeImpl geoFeatureSetCode1 = new GeoFeatureSetCodeImpl(); + geoFeatureSetCode1.setValue("Value1"); + geoFeatureSetCode1.setDescription(new InternationalString("code 1 desc")); + geoFeatureSetCode1.setId("CODE1"); + geoFeatureSetCode1.setName(new InternationalString("code 1")); + geoFeatureSetCode1.setParentId("CODE2"); + GeoFeatureSetCodeImpl geoFeatureSetCode2 = new GeoFeatureSetCodeImpl(); + geoFeatureSetCode2.setValue("Value2"); + geoFeatureSetCode2.setDescription(new InternationalString("code 2 desc")); + geoFeatureSetCode2.setId("CODE2"); + geoFeatureSetCode2.setName(new InternationalString("code 2")); + return List.of(geoFeatureSetCode1, geoFeatureSetCode2); + } + + public static GeoGridCodelist buildGeoGridCodelist() { + GeoGridCodelistImpl geoGridCodelist = new GeoGridCodelistImpl(); + setMaintainableArtefact(geoGridCodelist); + geoGridCodelist.setItems(getGridCodes()); + geoGridCodelist.setExtensions(getExtensions()); + geoGridCodelist.setPartial(true); + geoGridCodelist.setGridDefinition("DEFINITION"); + return geoGridCodelist; + } + + private static List getGridCodes() { + GridCodeImpl gridCode = new GridCodeImpl(); + gridCode.setGeoCell("Value1"); + gridCode.setDescription(new InternationalString("code 1 desc")); + gridCode.setId("CODE1"); + gridCode.setName(new InternationalString("code 1")); + gridCode.setParentId("CODE2"); + GridCodeImpl gridCode2 = new GridCodeImpl(); + gridCode2.setGeoCell("Value2"); + gridCode2.setDescription(new InternationalString("code 2 desc")); + gridCode2.setId("CODE2"); + gridCode2.setName(new InternationalString("code 2")); + return List.of(gridCode, gridCode2); + } + + private static List getAnnotations() { + AnnotationImpl annotation = new AnnotationImpl(); + annotation.setId("Annot"); + return List.of(annotation); + } + + public static OrganisationUnitScheme buildOrganisationUnitScheme() { + OrganisationUnitSchemeImpl organisationUnitScheme = new OrganisationUnitSchemeImpl(); + setMaintainableArtefact(organisationUnitScheme); + organisationUnitScheme.setVersion(Version.createFromString("1.0")); + organisationUnitScheme.setPartial(true); + OrganisationUnitImpl organisationUnit = new OrganisationUnitImpl(); + organisationUnit.setAnnotations(getAnnotations()); + organisationUnit.setContacts(getContacts()); + organisationUnit.setId("OrgUnit"); + organisationUnit.setName(new InternationalString("OrganisationUnit")); + organisationUnit.setDescription(new InternationalString("OrganisationUnit description")); + OrganisationUnitImpl organisationUnit2 = new OrganisationUnitImpl(); + organisationUnit2.setId("OrgUnit2"); + organisationUnit2.setName(new InternationalString("OrganisationUnit")); + organisationUnit.setHierarchy(List.of(organisationUnit2)); + organisationUnitScheme.setItems(List.of(organisationUnit, organisationUnit2)); + return organisationUnitScheme; + } + +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/TestUtils.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/TestUtils.java new file mode 100644 index 0000000..673962b --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/TestUtils.java @@ -0,0 +1,68 @@ +package com.epam.jsdmx.xml30.structure; + +import java.io.File; +import java.io.IOException; + +import javax.xml.XMLConstants; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; + +import org.xml.sax.SAXException; + +public final class TestUtils { + + public static final String CODELIST_XML = "/xml/codelist.xml"; + public static final String HIERARCHIES_XML = "/xml/hierarchy.xml"; + public static final String HIERARCHIES_NAMES_XML = "/xml/hierarchy_names.xml"; + public static final String CONCEPT_SCHEME_XML = "/xml/concept-scheme.xml"; + public static final String CATEGORISATION_XML = "/xml/categorisation.xml"; + public static final String DSD_XML = "/xml/dsd.xml"; + public static final String DSD_WITH_ENUM_FORMAT_XML = "/xml/dsd_with_enumFormat.xml"; + public static final String DATAFLOW_XML = "/xml/dataflow.xml"; + public static final String M_STRUCTURE_DEFINITION_XML = "/xml/mdsd.xml"; + public static final String METADATAFLOW_XML = "/xml/metadataflow.xml"; + public static final String REPRESENTATION_MAP_XML = "/xml/representation_map.xml"; + public static final String STRUCTURE_MAP_XML = "/xml/structure_map.xml"; + public static final String CATEGORY_SCHEME_XML = "/xml/category-scheme.xml"; + public static final String AGENCY_SCHEME_XML = "/xml/agency-scheme.xml"; + public static final String CATEGORY_SCHEME_MAP_XML = "/xml/category-scheme-map.xml"; + public static final String CONCEPT_SCHEME_MAP_XML = "/xml/concept-scheme-map.xml"; + public static final String DATA_CONSUMER_SCHEME_XML = "/xml/data-consumer-scheme.xml"; + public static final String DATA_PROVIDER_SCHEME_XML = "/xml/data-provider-scheme.xml"; + public static final String METADATA_PROVIDER_SCHEME_XML = "/xml/metadata-provider-scheme.xml"; + public static final String HIERARCHY_ASSOCIATION_XML = "/xml/hierarchy-association.xml"; + public static final String METADATA_CONSTRAINTS_XML = "/xml/metadata-constraints.xml"; + public static final String DATA_CONSTRAINTS_XML = "/xml/data-constraints.xml"; + public static final String DATA_CONSTRAINTS2_XML = "/xml/data-constraints-skip-validTo.xml"; + public static final String DATA_CONSTRAINTS_EMPTY_XML = "/xml/data-constraints-empty.xml"; + public static final String METADATA_PROVISION_AGREEMENT_XML = "/xml/metadata-provision-agreement.xml"; + public static final String ORGANISATION_SCHEME_MAP_XML = "/xml/organisation-scheme-map.xml"; + public static final String PROCESS_XML = "/xml/process.xml"; + public static final String PROVISION_AGREEMENT_XML = "/xml/provision-agreement.xml"; + public static final String REPORTING_TAXONOMY_XML = "/xml/reporting-taxonomy.xml"; + public static final String REPORTING_TAXONOMY_MAP_XML = "/xml/reporting-taxonomy-map.xml"; + public static final String VALUE_LIST_XML = "/xml/valuelist.xml"; + public static final String ORGANISATION_UNIT_SCHEME_XML = "/xml/organisation-unit-scheme.xml"; + public static final String GEOGRAPHICAL_CODELIST_XML = "/xml/geographical-codelist.xml"; + public static final String GEOGRID_CODELIST_XML = "/xml/geogrid-codelist.xml"; + + public static final String ALL_XML = "/xml/all.xml"; + + public static boolean validateXMLSchema(File xsdPath, File xmlPath) { + + try { + SchemaFactory factory = + SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + Schema schema = factory.newSchema(xsdPath); + Validator validator = schema.newValidator(); + validator.validate(new StreamSource(xmlPath)); + } catch (IOException | SAXException e) { + System.out.println("Exception: " + e.getMessage()); + return false; + } + return true; + } + +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/XsdToXmlTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/XsdToXmlTest.java new file mode 100644 index 0000000..7fa9af2 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/XsdToXmlTest.java @@ -0,0 +1,55 @@ +package com.epam.jsdmx.xml30.structure; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Objects; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.util.ResourceUtils; + +class XsdToXmlTest { + + public static final String XML_XSD_SCHEMAS_SDMXMESSAGE_XSD = "/xml/xsd/schemas/SDMXMessage.xsd"; + + @ParameterizedTest + @ValueSource(strings = { + TestUtils.CODELIST_XML, + TestUtils.HIERARCHIES_XML, + TestUtils.CONCEPT_SCHEME_XML, + TestUtils.CATEGORISATION_XML, + TestUtils.DSD_XML, + TestUtils.DATAFLOW_XML, + TestUtils.M_STRUCTURE_DEFINITION_XML, + TestUtils.METADATAFLOW_XML, + TestUtils.REPRESENTATION_MAP_XML, + TestUtils.STRUCTURE_MAP_XML, + TestUtils.CATEGORY_SCHEME_XML, + TestUtils.AGENCY_SCHEME_XML, + TestUtils.CATEGORY_SCHEME_MAP_XML, + TestUtils.CONCEPT_SCHEME_XML, + TestUtils.ALL_XML, + TestUtils.DATA_CONSUMER_SCHEME_XML, + TestUtils.DATA_PROVIDER_SCHEME_XML, + TestUtils.METADATA_PROVIDER_SCHEME_XML, + TestUtils.HIERARCHY_ASSOCIATION_XML, + TestUtils.METADATA_CONSTRAINTS_XML, + TestUtils.DATA_CONSTRAINTS_XML, + TestUtils.METADATA_PROVISION_AGREEMENT_XML, + TestUtils.ORGANISATION_SCHEME_MAP_XML, + TestUtils.PROCESS_XML, + TestUtils.PROVISION_AGREEMENT_XML, + TestUtils.REPORTING_TAXONOMY_XML, + TestUtils.REPORTING_TAXONOMY_MAP_XML, + TestUtils.VALUE_LIST_XML, + TestUtils.ORGANISATION_UNIT_SCHEME_XML, + TestUtils.GEOGRAPHICAL_CODELIST_XML, + TestUtils.GEOGRID_CODELIST_XML + }) + void xmlToXsd(String path) throws FileNotFoundException { + File fileXsd = ResourceUtils.getFile(Objects.requireNonNull(this.getClass().getResource(XML_XSD_SCHEMAS_SDMXMESSAGE_XSD))); + File fileXml = ResourceUtils.getFile(Objects.requireNonNull(this.getClass().getResource(path))); + Assertions.assertTrue(TestUtils.validateXMLSchema(fileXsd, fileXml)); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/AgencySchemeReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/AgencySchemeReaderTest.java new file mode 100644 index 0000000..760cdea --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/AgencySchemeReaderTest.java @@ -0,0 +1,42 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.AGENCY_SCHEME_XML; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.AgencyScheme; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class AgencySchemeReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(AGENCY_SCHEME_XML, minifyXml); + + AgencySchemeReader agencySchemeReader = createAgencySchemeReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(agencySchemeReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + AgencyScheme actual = artefacts.getAgencySchemes().iterator().next(); + AgencyScheme expected = MaintainableArtifactsTestUtils.buildAgencyScheme(); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/BaseXmlReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/BaseXmlReaderTest.java new file mode 100644 index 0000000..3492f00 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/BaseXmlReaderTest.java @@ -0,0 +1,246 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +public class BaseXmlReaderTest { + + AnnotableReader annotableReader = new AnnotableReader(); + NameableReader nameableReader = new NameableReader(); + HeaderReader headerReader = new HeaderReader(); + RepresentationReader representationReader = new RepresentationReader(nameableReader); + + AttributeListReader attributeListReader = new AttributeListReader(representationReader, annotableReader); + DimensionListReader dimensionListReader = new DimensionListReader(representationReader, annotableReader); + MeasureListReader measureListReader = new MeasureListReader(representationReader, annotableReader); + MemberSelectionReader memberSelectionReader = new MemberSelectionReader(); + ReleaseCalendarReader releaseCalendarReader = new ReleaseCalendarReader(); + + OrganisationReader organisationReader = new OrganisationReader(annotableReader, nameableReader); + + public XMLStreamReader createXmlStreamReaderInstance(String resourcePath, boolean minifyXml) throws XMLStreamException, IOException { + XMLInputFactory xmlInFact = XMLInputFactory.newInstance(); + return xmlInFact.createXMLStreamReader(createXmlInputSteam(resourcePath, minifyXml)); + } + + private InputStream createXmlInputSteam(String resourcePath, boolean minifyXml) throws IOException { + InputStream is = this.getClass().getResourceAsStream(resourcePath); + if (minifyXml) { + try (is) { + String xml = minifyXml(new String(is.readAllBytes(), StandardCharsets.UTF_8)); + return new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); + } + } + + return is; + } + + private String minifyXml(String xml) { + return xml.replaceAll("[\\n\\r]", "") + .replaceAll(">\\s+<", "><"); + } + + public CodelistReader createCodelistReader() { + return new CodelistReader(annotableReader, nameableReader, new CodelistExtensionReader(), new CodeImplReader()); + } + + public AgencySchemeReader createAgencySchemeReader() { + return new AgencySchemeReader( + annotableReader, + nameableReader, + organisationReader + ); + } + + public CategorisationReader createCategorisationReader() { + return new CategorisationReader(annotableReader, nameableReader); + } + + public CategorySchemeMapReader createCategorySchemeMapReader() { + return new CategorySchemeMapReader(annotableReader, nameableReader); + } + + public CategorySchemeReader createCategorySchemeReader() { + return new CategorySchemeReader(annotableReader, nameableReader); + } + + public ConceptSchemeMapReader createConceptSchemeMapReader() { + return new ConceptSchemeMapReader(annotableReader, nameableReader); + } + + public ConceptSchemeReader createConceptSchemeReader() { + return new ConceptSchemeReader( + annotableReader, + nameableReader, + representationReader + ); + } + + public DataConsumerSchemeReader createDataConsumerSchemeReader() { + return new DataConsumerSchemeReader( + annotableReader, + nameableReader, + organisationReader + ); + } + + public DataflowReader createDataFlowReader() { + return new DataflowReader(annotableReader, nameableReader); + } + + public DataConstraintReader createDataConstraintReader() { + return new DataConstraintReader( + annotableReader, + nameableReader, + releaseCalendarReader, + memberSelectionReader + ); + } + + public DataProviderSchemeReader createDataProviderSchemeReader() { + return new DataProviderSchemeReader( + annotableReader, + nameableReader, + organisationReader + ); + } + + public DataStructureDefinitionReader createDataStructureDefinitionReader() { + return new DataStructureDefinitionReader( + annotableReader, + nameableReader, + attributeListReader, + dimensionListReader, + measureListReader + ); + } + + public MetadataStructureDefinitionReader createMetadataStructureDefinitionReader() { + return new MetadataStructureDefinitionReader( + annotableReader, + nameableReader, + representationReader + ); + } + + public HierarchyAssociationReader createHierarchyAssociationReader() { + return new HierarchyAssociationReader(annotableReader, nameableReader); + } + + public HierarchyReader createHierarchyReader() { + return new HierarchyReader(annotableReader, nameableReader); + } + + public MetadataConstraintReader createMetadataConstraintReader() { + return new MetadataConstraintReader( + annotableReader, + nameableReader, + memberSelectionReader, + releaseCalendarReader + ); + } + + public MetadataflowReader createMetadataflowReader() { + return new MetadataflowReader(annotableReader, nameableReader); + } + + public MetadataProviderSchemeReader createMetadataProviderSchemeReader() { + return new MetadataProviderSchemeReader( + annotableReader, + nameableReader, + organisationReader + ); + } + + public MetadataProvisionAgreementReader createMetadataProvisionAgreementReader() { + return new MetadataProvisionAgreementReader(annotableReader, nameableReader); + } + + public OrganisationSchemeMapReader createOrganisationSchemeMapReader() { + return new OrganisationSchemeMapReader( + annotableReader, + nameableReader + ); + } + + public OrganisationUnitSchemeReader createOrganisationUnitSchemeReader() { + return new OrganisationUnitSchemeReader( + annotableReader, + nameableReader, + organisationReader + ); + } + + public ProcessReader createProcessReader() { + return new ProcessReader( + annotableReader, + nameableReader + ); + } + + public ProvisionAgreementReader createProvisionAgreementReader() { + return new ProvisionAgreementReader( + annotableReader, + nameableReader + ); + } + + public ReportingTaxonomyReader createReportingTaxonomyReader() { + return new ReportingTaxonomyReader( + annotableReader, + nameableReader + ); + } + + public ReportingTaxonomyMapReader createReportingTaxonomyMapReader() { + return new ReportingTaxonomyMapReader( + annotableReader, + nameableReader + ); + } + + public RepresentationMapReader createRepresentationMapReader() { + return new RepresentationMapReader( + annotableReader, + nameableReader + ); + } + + public StructureMapReader createStructureMapReader() { + return new StructureMapReader( + annotableReader, + nameableReader + ); + } + + public ValueListReader createValueListReader() { + return new ValueListReader( + annotableReader, + nameableReader + ); + } + + public GeographicCodelistReader createGeographicCodelistReader() { + return new GeographicCodelistReader( + annotableReader, + nameableReader, + new GeoFeatureSetCodeReader(), + new CodelistExtensionReader() + ); + } + + public GeoGridCodelistReader createGeoGridCodelistReader() { + return new GeoGridCodelistReader( + annotableReader, + nameableReader, + new CodelistExtensionReader(), + new GridCodeReader() + ); + } +} \ No newline at end of file diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CategorisationReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CategorisationReaderTest.java new file mode 100644 index 0000000..f2ba110 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CategorisationReaderTest.java @@ -0,0 +1,42 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Categorisation; +import com.epam.jsdmx.infomodel.sdmx30.CategorisationImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml30.structure.TestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class CategorisationReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(TestUtils.CATEGORISATION_XML, minifyXml); + + CategorisationReader categorisationReader = createCategorisationReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(categorisationReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + Categorisation actual = artefacts.getCategorisations().iterator().next(); + CategorisationImpl expected = MaintainableArtifactsTestUtils.buildCategorisation(); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeMapReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeMapReaderTest.java new file mode 100644 index 0000000..14dc99f --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeMapReaderTest.java @@ -0,0 +1,42 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.CATEGORY_SCHEME_MAP_XML; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeMap; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class CategorySchemeMapReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(CATEGORY_SCHEME_MAP_XML, minifyXml); + + CategorySchemeMapReader categorySchemeMapReader = createCategorySchemeMapReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(categorySchemeMapReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + CategorySchemeMap actual = artefacts.getCategorySchemeMaps().iterator().next(); + CategorySchemeMap expected = MaintainableArtifactsTestUtils.buildCategorySchemeMap(); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeReaderTest.java new file mode 100644 index 0000000..868bc15 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CategorySchemeReaderTest.java @@ -0,0 +1,49 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.CATEGORY_SCHEME_XML; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Category; +import com.epam.jsdmx.infomodel.sdmx30.CategoryScheme; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class CategorySchemeReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(CATEGORY_SCHEME_XML, minifyXml); + + CategorySchemeReader categorySchemeReader = createCategorySchemeReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(categorySchemeReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + CategoryScheme actualCatScheme = artefacts.getCategorySchemes().iterator().next(); + CategorySchemeImpl expectedCatScheme = MaintainableArtifactsTestUtils.buildCategoryScheme(); + + //then + List actualCategorySchemeItems = actualCatScheme.getItems(); + List expectedCategorySchemeItems = expectedCatScheme.getItems(); + + Assertions.assertEquals(expectedCatScheme, actualCatScheme); + Assertions.assertEquals(expectedCategorySchemeItems, actualCategorySchemeItems); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CodelistReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CodelistReaderTest.java new file mode 100644 index 0000000..642cce4 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/CodelistReaderTest.java @@ -0,0 +1,44 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Codelist; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml30.structure.TestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class CodelistReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(TestUtils.CODELIST_XML, minifyXml); + + CodelistReader codelistReader = createCodelistReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(codelistReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + Codelist actual = artefacts.getCodelists().iterator().next(); + CodelistImpl expected = MaintainableArtifactsTestUtils.buildCodeList(); + + Assertions.assertTrue(expected.deepEquals(actual)); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeMapReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeMapReaderTest.java new file mode 100644 index 0000000..99d0ee2 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeMapReaderTest.java @@ -0,0 +1,42 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.CONCEPT_SCHEME_MAP_XML; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeMap; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class ConceptSchemeMapReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(CONCEPT_SCHEME_MAP_XML, minifyXml); + + ConceptSchemeMapReader conceptSchemeMapReader = createConceptSchemeMapReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(conceptSchemeMapReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + ConceptSchemeMap actual = artefacts.getConceptSchemeMaps().iterator().next(); + ConceptSchemeMap expected = MaintainableArtifactsTestUtils.buildConceptSchemeMap(); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeReaderTest.java new file mode 100644 index 0000000..837d997 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ConceptSchemeReaderTest.java @@ -0,0 +1,68 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.CONCEPT_SCHEME_XML; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ConceptScheme; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class ConceptSchemeReaderTest extends BaseXmlReaderTest { + + @Test + void testEnumerationFormat() throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance("/xml/concept-scheme_with_enum_format.xml", true); + + ConceptSchemeReader conceptSchemeReader = createConceptSchemeReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(conceptSchemeReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + ConceptScheme actual = artefacts.getConceptSchemes().iterator().next(); + + assertNotNull(actual); + } + + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(CONCEPT_SCHEME_XML, minifyXml); + + ConceptSchemeReader conceptSchemeReader = createConceptSchemeReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(conceptSchemeReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + ConceptScheme actual = artefacts.getConceptSchemes().iterator().next(); + ConceptSchemeImpl expected = MaintainableArtifactsTestUtils.buildConceptScheme(); + assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataConstraintReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataConstraintReaderTest.java new file mode 100644 index 0000000..1cf0162 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataConstraintReaderTest.java @@ -0,0 +1,116 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.DATA_CONSTRAINTS2_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.DATA_CONSTRAINTS_EMPTY_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.DATA_CONSTRAINTS_XML; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.time.Instant; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.CascadeValue; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionImpl; +import com.epam.jsdmx.infomodel.sdmx30.CubeRegionKeyImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.MemberValueImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendarImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class DataConstraintReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(DATA_CONSTRAINTS_XML, minifyXml); + + DataConstraintReader dataConstraintReader = createDataConstraintReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(dataConstraintReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + DataConstraint actual = artefacts.getDataConstraints().iterator().next(); + DataConstraint expected = MaintainableArtifactsTestUtils.buildDataConstraint(); + + assertTrue(expected.deepEquals(actual)); + } + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void readWhenValidToIsNull(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(DATA_CONSTRAINTS2_XML, minifyXml); + + DataConstraintReader dataConstraintReader = createDataConstraintReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(dataConstraintReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + DataConstraint actual = artefacts.getDataConstraints().iterator().next(); + DataConstraint expected = createDataConstraint(); + + assertTrue(expected.deepEquals(actual)); + } + + private static DataConstraintImpl createDataConstraint() { + DataConstraintImpl dataConstraint = MaintainableArtifactsTestUtils.buildDataConstraint(); + dataConstraint.setDataContentKeys(List.of()); + CubeRegionKeyImpl cubeRegionKey1 = new CubeRegionKeyImpl(); + cubeRegionKey1.setComponentId("CubeReg"); + cubeRegionKey1.setIncluded(true); + cubeRegionKey1.setRemovePrefix(true); + cubeRegionKey1.setValidFrom(Instant.parse("2020-04-12T12:00:00.000000Z")); + MemberValueImpl memberValue = new MemberValueImpl(); + memberValue.setValue("MEM"); + memberValue.setCascadeValue(CascadeValue.EXCLUDE_ROOT); + cubeRegionKey1.setSelectionValues(List.of(memberValue)); + CubeRegionImpl cubeRegion = new CubeRegionImpl(); + cubeRegion.setIncluded(true); + cubeRegion.setCubeRegionKeys(List.of(cubeRegionKey1)); + dataConstraint.setCubeRegions(List.of(cubeRegion)); + + return dataConstraint; + } + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void readEmptyDataConstraint(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(DATA_CONSTRAINTS_EMPTY_XML, minifyXml); + + DataConstraintReader dataConstraintReader = createDataConstraintReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(dataConstraintReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + DataConstraint actual = artefacts.getDataConstraints().iterator().next(); + DataConstraintImpl expected = MaintainableArtifactsTestUtils.buildDataConstraint(); + expected.setDataContentKeys(List.of()); + expected.setCubeRegions(List.of()); + expected.setReleaseCalendar(new ReleaseCalendarImpl()); + + assertTrue(expected.deepEquals(actual)); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataConsumerSchemeReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataConsumerSchemeReaderTest.java new file mode 100644 index 0000000..02315e8 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataConsumerSchemeReaderTest.java @@ -0,0 +1,42 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.DATA_CONSUMER_SCHEME_XML; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerScheme; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class DataConsumerSchemeReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(DATA_CONSUMER_SCHEME_XML, minifyXml); + + DataConsumerSchemeReader dataConsumerSchemeReader = createDataConsumerSchemeReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(dataConsumerSchemeReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + DataConsumerScheme actual = artefacts.getDataConsumerSchemes().iterator().next(); + DataConsumerScheme expected = MaintainableArtifactsTestUtils.buildDataConsumerScheme(); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataProviderSchemeReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataProviderSchemeReaderTest.java new file mode 100644 index 0000000..3d71c52 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataProviderSchemeReaderTest.java @@ -0,0 +1,41 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderScheme; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml30.structure.TestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class DataProviderSchemeReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(TestUtils.DATA_PROVIDER_SCHEME_XML, minifyXml); + + DataProviderSchemeReader dataProviderSchemeReader = createDataProviderSchemeReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(dataProviderSchemeReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + DataProviderScheme actual = artefacts.getDataProviderSchemes().iterator().next(); + DataProviderScheme expected = MaintainableArtifactsTestUtils.buildDataProviderScheme(); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataStructureDefinitionReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataStructureDefinitionReaderTest.java new file mode 100644 index 0000000..4632d76 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataStructureDefinitionReaderTest.java @@ -0,0 +1,82 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.DSD_WITH_ENUM_FORMAT_XML; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.DataAttribute; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinition; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeRef; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class DataStructureDefinitionReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(DSD_WITH_ENUM_FORMAT_XML, minifyXml); + + DataStructureDefinitionReader dataStructureDefinitionReader = createDataStructureDefinitionReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(dataStructureDefinitionReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + DataStructureDefinition actual = artefacts.getDataStructures().iterator().next(); + DataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + expected.setAttributeDescriptor(MaintainableArtifactsTestUtils.fillAttributeDescriptor()); + expected.setDimensionDescriptor(MaintainableArtifactsTestUtils.fillDimensionDescriptor()); + expected.setMeasureDescriptor(MaintainableArtifactsTestUtils.fillMeasureDescriptor()); + List attributeRefs = expected.getAttributeDescriptor().getMetadataAttributes(); + List refs = List.of(attributeRefs.get(0), attributeRefs.get(1)); + expected.getAttributeDescriptor().setMetadataAttributes(refs); + assertTrue(expected.deepEquals(actual)); + } + + @Test + void testDataflowAttributeRelationship() throws Exception { + //given + XMLStreamReader reader = createXmlStreamReaderInstance("/xml/dsd_with_df_attr_relationship.xml", true); + + DataStructureDefinitionReader dataStructureDefinitionReader = createDataStructureDefinitionReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(dataStructureDefinitionReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + DataStructureDefinition actual = artefacts.getDataStructures().iterator().next(); + + AttributeDescriptor attributeDescriptor = actual.getAttributeDescriptor(); + DataAttribute dataAttribute = attributeDescriptor.getComponents().get(0); + assertThat(dataAttribute.getAttributeRelationship()).isNull(); + + List metaAttributes = actual.getMetaAttributeReferences(); + MetadataAttributeRef metaAttribute = metaAttributes.get(0); + assertThat(metaAttribute.getMetadataRelationship()).isNull(); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataflowReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataflowReaderTest.java new file mode 100644 index 0000000..5dcef72 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/DataflowReaderTest.java @@ -0,0 +1,44 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.DATAFLOW_XML; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Dataflow; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class DataflowReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(DATAFLOW_XML, minifyXml); + + DataflowReader dataflowReader = createDataFlowReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(dataflowReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + Dataflow actual = artefacts.getDataflows().iterator().next(); + DataflowImpl expected = MaintainableArtifactsTestUtils.buildDataFlow(); + assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/GeoGridCodelistReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/GeoGridCodelistReaderTest.java new file mode 100644 index 0000000..e711067 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/GeoGridCodelistReaderTest.java @@ -0,0 +1,43 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.GeoGridCodelist; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml30.structure.TestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class GeoGridCodelistReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(TestUtils.GEOGRID_CODELIST_XML, minifyXml); + + GeoGridCodelistReader codelistReader = createGeoGridCodelistReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(codelistReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + GeoGridCodelist actual = artefacts.getGeoGridCodelists().iterator().next(); + GeoGridCodelist expected = MaintainableArtifactsTestUtils.buildGeoGridCodelist(); + + Assertions.assertTrue(expected.deepEquals(actual)); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/GeographicCodelistReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/GeographicCodelistReaderTest.java new file mode 100644 index 0000000..1926238 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/GeographicCodelistReaderTest.java @@ -0,0 +1,43 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.GeographicCodelist; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml30.structure.TestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class GeographicCodelistReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(TestUtils.GEOGRAPHICAL_CODELIST_XML, minifyXml); + + GeographicCodelistReader codelistReader = createGeographicCodelistReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(codelistReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + GeographicCodelist actual = artefacts.getGeographicCodelists().iterator().next(); + GeographicCodelist expected = MaintainableArtifactsTestUtils.buildGeographicCodelist(); + + Assertions.assertTrue(expected.deepEquals(actual)); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/HierarchyAssociationReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/HierarchyAssociationReaderTest.java new file mode 100644 index 0000000..31c3c8c --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/HierarchyAssociationReaderTest.java @@ -0,0 +1,42 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.HIERARCHY_ASSOCIATION_XML; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyAssociation; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class HierarchyAssociationReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(HIERARCHY_ASSOCIATION_XML, minifyXml); + HierarchyAssociationReader hierarchyAssociationReader = createHierarchyAssociationReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(hierarchyAssociationReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + HierarchyAssociation actual = artefacts.getHierarchyAssociations().iterator().next(); + HierarchyAssociation expected = MaintainableArtifactsTestUtils.buildHierarchyAssociation(); + assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/HierarchyReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/HierarchyReaderTest.java new file mode 100644 index 0000000..0241a4e --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/HierarchyReaderTest.java @@ -0,0 +1,43 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Hierarchy; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml30.structure.TestUtils; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class HierarchyReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(TestUtils.HIERARCHIES_XML, minifyXml); + HierarchyReader hierarchyReader = createHierarchyReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(hierarchyReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + Hierarchy actual = artefacts.getHierarchies().iterator().next(); + HierarchyImpl expected = MaintainableArtifactsTestUtils.buildHierarchy(); + assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataConstraintReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataConstraintReaderTest.java new file mode 100644 index 0000000..166f906 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataConstraintReaderTest.java @@ -0,0 +1,42 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.METADATA_CONSTRAINTS_XML; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MetadataConstraint; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class MetadataConstraintReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(METADATA_CONSTRAINTS_XML, minifyXml); + + MetadataConstraintReader metadataConstraintReader = createMetadataConstraintReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(metadataConstraintReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + MetadataConstraint actual = artefacts.getMetadataConstraints().iterator().next(); + MetadataConstraint expected = MaintainableArtifactsTestUtils.buildMetadataConstraint(false); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataProviderSchemeReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataProviderSchemeReaderTest.java new file mode 100644 index 0000000..3e18824 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataProviderSchemeReaderTest.java @@ -0,0 +1,41 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderScheme; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml30.structure.TestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class MetadataProviderSchemeReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(TestUtils.METADATA_PROVIDER_SCHEME_XML, minifyXml); + + MetadataProviderSchemeReader dataProviderSchemeReader = createMetadataProviderSchemeReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(dataProviderSchemeReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + MetadataProviderScheme actual = artefacts.getMetadataProviderSchemes().iterator().next(); + MetadataProviderScheme expected = MaintainableArtifactsTestUtils.buildMetadataProviderScheme(); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataProvisionAgreementReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataProvisionAgreementReaderTest.java new file mode 100644 index 0000000..cda1f98 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataProvisionAgreementReaderTest.java @@ -0,0 +1,42 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.METADATA_PROVISION_AGREEMENT_XML; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProvisionAgreement; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class MetadataProvisionAgreementReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(METADATA_PROVISION_AGREEMENT_XML, minifyXml); + + MetadataProvisionAgreementReader metadataProvisionAgreementReader = createMetadataProvisionAgreementReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(metadataProvisionAgreementReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + MetadataProvisionAgreement actual = artefacts.getMetadataProvisionAgreements().iterator().next(); + MetadataProvisionAgreement expected = MaintainableArtifactsTestUtils.buildMetadataProvisionAgreement(); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataStructureDefinitionReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataStructureDefinitionReaderTest.java new file mode 100644 index 0000000..f380e1c --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataStructureDefinitionReaderTest.java @@ -0,0 +1,44 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.M_STRUCTURE_DEFINITION_XML; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinition; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinitionImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class MetadataStructureDefinitionReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(M_STRUCTURE_DEFINITION_XML, minifyXml); + + MetadataStructureDefinitionReader metadataStructureDefinitionReader = createMetadataStructureDefinitionReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(metadataStructureDefinitionReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + MetadataStructureDefinition actual = artefacts.getMetadataStructureDefinitions().iterator().next(); + MetadataStructureDefinitionImpl expected = MaintainableArtifactsTestUtils.buildMetadataStructureDefinition(); + assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataflowReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataflowReaderTest.java new file mode 100644 index 0000000..cea25b7 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/MetadataflowReaderTest.java @@ -0,0 +1,44 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Metadataflow; +import com.epam.jsdmx.infomodel.sdmx30.MetadataflowImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml30.structure.TestUtils; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class MetadataflowReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(TestUtils.METADATAFLOW_XML, minifyXml); + + MetadataflowReader metadataflowReader = createMetadataflowReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(metadataflowReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + Metadataflow actual = artefacts.getMetadataflows().iterator().next(); + MetadataflowImpl expected = MaintainableArtifactsTestUtils.buildMetadataFlow(); + assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/OrganisationSchemeMapReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/OrganisationSchemeMapReaderTest.java new file mode 100644 index 0000000..cf4886c --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/OrganisationSchemeMapReaderTest.java @@ -0,0 +1,42 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.ORGANISATION_SCHEME_MAP_XML; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationSchemeMap; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class OrganisationSchemeMapReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(ORGANISATION_SCHEME_MAP_XML, minifyXml); + + OrganisationSchemeMapReader categorySchemeMapReader = createOrganisationSchemeMapReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(categorySchemeMapReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + OrganisationSchemeMap actual = artefacts.getOrganisationSchemeMaps().iterator().next(); + OrganisationSchemeMap expected = MaintainableArtifactsTestUtils.buildOrganisationSchemeMap(); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/OrganisationUnitSchemeReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/OrganisationUnitSchemeReaderTest.java new file mode 100644 index 0000000..13c938f --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/OrganisationUnitSchemeReaderTest.java @@ -0,0 +1,43 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitScheme; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml30.structure.TestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class OrganisationUnitSchemeReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(TestUtils.ORGANISATION_UNIT_SCHEME_XML, minifyXml); + + OrganisationUnitSchemeReader categorySchemeMapReader = createOrganisationUnitSchemeReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(categorySchemeMapReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + OrganisationUnitScheme actual = artefacts.getOrganisationUnitSchemes().iterator().next(); + OrganisationUnitScheme expected = MaintainableArtifactsTestUtils.buildOrganisationUnitScheme(); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ProcessReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ProcessReaderTest.java new file mode 100644 index 0000000..7d5c43b --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ProcessReaderTest.java @@ -0,0 +1,42 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.PROCESS_XML; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Process; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class ProcessReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(PROCESS_XML, minifyXml); + + ProcessReader processReader = createProcessReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(processReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + Process actual = artefacts.getProcesses().iterator().next(); + Process expected = MaintainableArtifactsTestUtils.buildProcess(); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ProvisionAgreementReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ProvisionAgreementReaderTest.java new file mode 100644 index 0000000..1a04808 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ProvisionAgreementReaderTest.java @@ -0,0 +1,42 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.PROVISION_AGREEMENT_XML; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ProvisionAgreement; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class ProvisionAgreementReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(PROVISION_AGREEMENT_XML, minifyXml); + + ProvisionAgreementReader provisionAgreementReader = createProvisionAgreementReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(provisionAgreementReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + ProvisionAgreement actual = artefacts.getProvisionAgreements().iterator().next(); + ProvisionAgreement expected = MaintainableArtifactsTestUtils.buildProvisionAgreement(); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyMapReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyMapReaderTest.java new file mode 100644 index 0000000..9b49651 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyMapReaderTest.java @@ -0,0 +1,42 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.REPORTING_TAXONOMY_MAP_XML; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyMap; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class ReportingTaxonomyMapReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(REPORTING_TAXONOMY_MAP_XML, minifyXml); + + ReportingTaxonomyMapReader reportingTaxonomyMapReader = createReportingTaxonomyMapReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(reportingTaxonomyMapReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + ReportingTaxonomyMap actual = artefacts.getReportingTaxonomyMaps().iterator().next(); + ReportingTaxonomyMap expected = MaintainableArtifactsTestUtils.buildReportingTaxonomyMap(); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyReaderTest.java new file mode 100644 index 0000000..1745697 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ReportingTaxonomyReaderTest.java @@ -0,0 +1,42 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.REPORTING_TAXONOMY_XML; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomy; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class ReportingTaxonomyReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(REPORTING_TAXONOMY_XML, minifyXml); + + ReportingTaxonomyReader reportingTaxonomyReader = createReportingTaxonomyReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(reportingTaxonomyReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + ReportingTaxonomy actual = artefacts.getReportingTaxonomies().iterator().next(); + ReportingTaxonomy expected = MaintainableArtifactsTestUtils.buildReportingTaxonomy(); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/RepresentationMapReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/RepresentationMapReaderTest.java new file mode 100644 index 0000000..aadb581 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/RepresentationMapReaderTest.java @@ -0,0 +1,45 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.REPRESENTATION_MAP_XML; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMap; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class RepresentationMapReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(REPRESENTATION_MAP_XML, minifyXml); + + RepresentationMapReader representationMapReader = createRepresentationMapReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(representationMapReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + RepresentationMap actual = artefacts.getRepresentationMaps().iterator().next(); + RepresentationMapImpl expected = MaintainableArtifactsTestUtils.buildRepresentationMap(); + assertEquals(actual.getRepresentationMappings(), expected.getRepresentationMappings()); + assertEquals(actual, expected); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/StructureMapReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/StructureMapReaderTest.java new file mode 100644 index 0000000..5f7de22 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/StructureMapReaderTest.java @@ -0,0 +1,43 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import static com.epam.jsdmx.xml30.structure.TestUtils.STRUCTURE_MAP_XML; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.StructureMap; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class StructureMapReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(STRUCTURE_MAP_XML, minifyXml); + + StructureMapReader structureMapReader = createStructureMapReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of(structureMapReader) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + StructureMap actual = artefacts.getStructureMaps().iterator().next(); + StructureMap expected = MaintainableArtifactsTestUtils.buildStructureMap(); + assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ValueListReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ValueListReaderTest.java new file mode 100644 index 0000000..e64833d --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/ValueListReaderTest.java @@ -0,0 +1,41 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ValueList; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml30.structure.TestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class ValueListReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void read(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(TestUtils.VALUE_LIST_XML, minifyXml); + + ValueListReader valueListReader = createValueListReader(); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, List.of(valueListReader)); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + //then + ValueList actual = artefacts.getValueLists().iterator().next(); + ValueList expected = MaintainableArtifactsTestUtils.buildValueList(); + + Assertions.assertEquals(expected, actual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/XmlStructureReaderTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/XmlStructureReaderTest.java new file mode 100644 index 0000000..1f81edf --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/reader/XmlStructureReaderTest.java @@ -0,0 +1,99 @@ +package com.epam.jsdmx.xml30.structure.reader; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.Categorisation; +import com.epam.jsdmx.infomodel.sdmx30.CategoryScheme; +import com.epam.jsdmx.infomodel.sdmx30.Codelist; +import com.epam.jsdmx.infomodel.sdmx30.ConceptScheme; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinition; +import com.epam.jsdmx.infomodel.sdmx30.Dataflow; +import com.epam.jsdmx.infomodel.sdmx30.Hierarchy; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinition; +import com.epam.jsdmx.infomodel.sdmx30.Metadataflow; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMap; +import com.epam.jsdmx.infomodel.sdmx30.StructureMap; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml30.structure.TestUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class XmlStructureReaderTest extends BaseXmlReaderTest { + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void readAll(boolean minifyXml) throws XMLStreamException, URISyntaxException, IOException { + //given + XMLStreamReader reader = createXmlStreamReaderInstance(TestUtils.ALL_XML, minifyXml); + + XmlStructureReader xmlStructureReader = new XmlStructureReader( + headerReader, + List.of( + createCategorisationReader(), + createCategorySchemeReader(), + createConceptSchemeReader(), + createCodelistReader(), + createDataFlowReader(), + createDataStructureDefinitionReader(), + createMetadataStructureDefinitionReader(), + createHierarchyReader(), + createRepresentationMapReader(), + createStructureMapReader(), + createMetadataflowReader(), + createDataConstraintReader() + ) + ); + + //when + Artefacts artefacts = xmlStructureReader.read(reader); + + Categorisation categorisationActual = artefacts.getCategorisations().iterator().next(); + CategoryScheme categorySchemeActual = artefacts.getCategorySchemes().iterator().next(); + ConceptScheme conceptSchemeActual = artefacts.getConceptSchemes().iterator().next(); + Codelist codelistActual = artefacts.getCodelists().iterator().next(); + Dataflow dataflowActual = artefacts.getDataflows().iterator().next(); + DataStructureDefinition dataStructureDefinitionActual = artefacts.getDataStructures().iterator().next(); + Hierarchy hierarchyActual = artefacts.getHierarchies().iterator().next(); + Metadataflow metadataflowActual = artefacts.getMetadataflows().iterator().next(); + MetadataStructureDefinition metadataStructureDefinitionActual = artefacts.getMetadataStructureDefinitions().iterator().next(); + RepresentationMap representationMapActual = artefacts.getRepresentationMaps().iterator().next(); + StructureMap structureMapActual = artefacts.getStructureMaps().iterator().next(); + DataConstraint dataConstraintActual = artefacts.getDataConstraints().iterator().next(); + + Categorisation categorisationExpected = MaintainableArtifactsTestUtils.buildCategorisation(); + CategoryScheme categorySchemeExpected = MaintainableArtifactsTestUtils.buildCategoryScheme(); + ConceptScheme conceptSchemeExpected = MaintainableArtifactsTestUtils.buildConceptScheme(); + Codelist codelistExpected = MaintainableArtifactsTestUtils.buildCodeList(); + Dataflow dataflowExpected = MaintainableArtifactsTestUtils.buildDataFlow(); + DataStructureDefinition dataStructureDefinitionExpected = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + Hierarchy hierarchyExpected = MaintainableArtifactsTestUtils.buildHierarchy(); + Metadataflow metadataflowExpected = MaintainableArtifactsTestUtils.buildMetadataFlow(); + MetadataStructureDefinition metadataStructureDefinitionExpected = MaintainableArtifactsTestUtils.buildMetadataStructureDefinition(); + RepresentationMap representationMapExpected = MaintainableArtifactsTestUtils.buildRepresentationMap(); + StructureMap structureMapExpected = MaintainableArtifactsTestUtils.buildStructureMap(); + DataConstraint dataConstraintExpected = MaintainableArtifactsTestUtils.buildDataConstraint(); + + //then + Assertions.assertEquals(conceptSchemeExpected, conceptSchemeActual); + Assertions.assertEquals(dataflowExpected, dataflowActual); + Assertions.assertEquals(codelistExpected, codelistActual); + Assertions.assertEquals(categorisationExpected, categorisationActual); + Assertions.assertEquals(dataStructureDefinitionExpected, dataStructureDefinitionActual); + Assertions.assertEquals(metadataflowExpected, metadataflowActual); + Assertions.assertEquals(metadataStructureDefinitionExpected, metadataStructureDefinitionActual); + Assertions.assertEquals(representationMapExpected, representationMapActual); + Assertions.assertEquals(structureMapExpected, structureMapActual); + Assertions.assertEquals(categorySchemeExpected, categorySchemeActual); + Assertions.assertEquals(hierarchyExpected, hierarchyActual); + Assertions.assertEquals(dataConstraintExpected, dataConstraintActual); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/AgencySchemeWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/AgencySchemeWriterTest.java new file mode 100644 index 0000000..c42bca9 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/AgencySchemeWriterTest.java @@ -0,0 +1,52 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils.buildAgencyScheme; +import static com.epam.jsdmx.xml30.structure.TestUtils.AGENCY_SCHEME_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.AgencySchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class AgencySchemeWriterTest extends BaseXmlWriterTest { + + @Test + void writeAgencyScheme() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + AgencySchemeWriter agencySchemeWriter = createAgencySchemeWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(agencySchemeWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + AgencySchemeImpl agencyScheme = buildAgencyScheme(); + artefacts.getAgencySchemes().add(agencyScheme); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(AGENCY_SCHEME_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/BaseXmlWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/BaseXmlWriterTest.java new file mode 100644 index 0000000..3551e3f --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/BaseXmlWriterTest.java @@ -0,0 +1,359 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.time.Instant; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.Party; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; +import com.epam.jsdmx.serializer.common.StubDataStructureLocalRepresentationAdapter; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultHeaderProvider; +import com.epam.jsdmx.serializer.sdmx30.common.DefaultReferenceAdapter; +import com.epam.jsdmx.serializer.sdmx30.common.Header; + +import lombok.SneakyThrows; +import org.junit.jupiter.api.BeforeEach; + +public abstract class BaseXmlWriterTest { + NameableWriter nameableWriter = new NameableWriter(); + AnnotableWriter annotableWriter = new AnnotableWriter(); + ReferenceAdapter referenceAdapter = new DefaultReferenceAdapter(); + UrnWriter urnWriter = new UrnWriter(referenceAdapter); + CommonAttributesWriter commonAttributesWriter = new CommonAttributesWriter(urnWriter); + LinksWriter linksWriter = new LinksWriter(urnWriter); + + ItemSchemeMapWriter itemSchemeMapWriter = new ItemSchemeMapWriter(urnWriter); + + ContactWriter contactWriter = new ContactWriter(); + ReleaseCalenderWriter releaseCalenderWriter = new ReleaseCalenderWriter(); + + MemberSelectionWriter memberSelectionWriter = new MemberSelectionWriter(); + + OrganisationWriter organisationWriter = new OrganisationWriter(contactWriter, annotableWriter, nameableWriter); + + RepresentationWriter representationWriter = new RepresentationWriter(urnWriter); + + DefaultHeaderProvider defaultHeaderProvider = mock(DefaultHeaderProvider.class); + + HeaderWriter headerWriter = new HeaderWriter(defaultHeaderProvider); + + @BeforeEach + @SneakyThrows + void setup() { + Header header = new Header(); + header.setId("HED1"); + header.setName(new InternationalString("HeaderTest")); + header.setTest(true); + header.setReceivers(List.of(new Party("id", new InternationalString("str")))); + header.setSender(new Party("id", new InternationalString())); + header.setPrepared(Instant.parse("2023-04-17T10:11:16Z")); + when(defaultHeaderProvider.provide()).thenReturn(header); + } + + public CategorisationWriter createCategorisationWriter() { + return new CategorisationWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + urnWriter + ); + } + + public CodelistWriter createCodelistWriter() { + return new CodelistWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + new CodeWriterImpl(urnWriter, nameableWriter, annotableWriter), + new CodeListExtensionWriter(urnWriter) + ); + } + + public GeographicCodelistWriter createGeographicCodelistWriter() { + return new GeographicCodelistWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + new GeoFeatureSetCodeWriter(urnWriter, nameableWriter, annotableWriter), + new CodeListExtensionWriter(urnWriter) + ); + } + + public GeoGridCodelistWriter createGeoGridCodelistWriter() { + return new GeoGridCodelistWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + new CodeListExtensionWriter(urnWriter), + new GridCodeWriter(urnWriter, nameableWriter, annotableWriter) + ); + } + + public ConceptSchemeWriter createConceptSchemeWriter() { + return new ConceptSchemeWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + representationWriter + ); + } + + public CategorySchemeWriter createCategorySchemeWriter() { + return new CategorySchemeWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter + ); + } + + public DataflowWriter createDataflowWriter() { + return new DataflowWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter + ); + } + + public DataStructureDefinitionWriter createDataStructureDefinitionWriter() { + var attributeListWriter = new AttributeListWriter(annotableWriter, representationWriter); + var dimensionListWriter = new DimensionListWriter(annotableWriter, representationWriter); + var measureListWriter = new MeasureListWriter(annotableWriter, representationWriter); + var groupDimensionListWriter = new GroupDimensionListWriter(annotableWriter); + return new DataStructureDefinitionWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + attributeListWriter, + dimensionListWriter, + measureListWriter, + groupDimensionListWriter, + new StubDataStructureLocalRepresentationAdapter() + ); + } + + public HierarchyWriter createHierarchyWriter() { + return new HierarchyWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + urnWriter + ); + } + + public MetadataflowWriter createMetadataflowWriter() { + return new MetadataflowWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter + ); + } + + public MetadataStructureDefinitionWriter createMetadataStructureDefinitionWriter() { + return new MetadataStructureDefinitionWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + representationWriter + ); + } + + public RepresentationMapWriter createRepresentationMapWriter() { + return new RepresentationMapWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + urnWriter + ); + } + + public StructureMapWriter createStructureMapWriter() { + return new StructureMapWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter + ); + } + + public AgencySchemeWriter createAgencySchemeWriter() { + return new AgencySchemeWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + organisationWriter + ); + } + + public HierarchyAssociationWriter createHierarchyAssociationWriter() { + return new HierarchyAssociationWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter + ); + } + + public CategorySchemeMapWriter createCategorySchemeMapWriter() { + return new CategorySchemeMapWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + itemSchemeMapWriter + ); + } + + public ConceptSchemeMapWriter createConceptSchemeMapWriter() { + return new ConceptSchemeMapWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + itemSchemeMapWriter + ); + } + + public DataConsumerSchemeWriter createDataConsumerSchemeWriter() { + return new DataConsumerSchemeWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + organisationWriter + ); + } + + public DataProviderSchemeWriter createDataProviderSchemeWriter() { + return new DataProviderSchemeWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + organisationWriter + ); + } + + public MetadataProviderSchemeWriter createMetadataProviderSchemeWriter() { + return new MetadataProviderSchemeWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + organisationWriter + ); + } + + public MetadataConstraintWriter createMetadataConstraintWriter() { + return new MetadataConstraintWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + releaseCalenderWriter, + memberSelectionWriter + ); + } + + public MetadataProvisionAgreementWriter createMetadataProvisionAgreementWriter() { + return new MetadataProvisionAgreementWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter + ); + } + + public OrganisationSchemeMapWriter createOrganisationSchemeMapWriter() { + return new OrganisationSchemeMapWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + itemSchemeMapWriter, + urnWriter + ); + } + + public OrganisationUnitSchemeWriter createOrganisationUnitSchemeWriter() { + return new OrganisationUnitSchemeWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + organisationWriter + ); + } + + public ProcessWriter createProcessWriter() { + return new ProcessWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter + ); + } + + public ProvisionAgreementWriter createProvisionAgreementWriter() { + return new ProvisionAgreementWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter + ); + } + + public ReportingTaxonomyWriter createReportingTaxonomyWriter() { + return new ReportingTaxonomyWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter + ); + } + + public ReportingTaxonomyMapWriter createReportingTaxonomyMapWriter() { + return new ReportingTaxonomyMapWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + itemSchemeMapWriter + ); + } + + public ValueListWriter createValueListWriter() { + return new ValueListWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter + ); + } + + public DataConstraintWriter createDataConstraintWriter() { + return new DataConstraintWriter( + nameableWriter, + annotableWriter, + commonAttributesWriter, + linksWriter, + releaseCalenderWriter, + memberSelectionWriter + ); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CategorisationWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CategorisationWriterTest.java new file mode 100644 index 0000000..7d3953c --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CategorisationWriterTest.java @@ -0,0 +1,52 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.CATEGORISATION_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorisationImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class CategorisationWriterTest extends BaseXmlWriterTest { + + @Test + void writeCategorisation() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + CategorisationWriter categorisationWriter = createCategorisationWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(categorisationWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + CategorisationImpl categorisation = MaintainableArtifactsTestUtils.buildCategorisation(); + artefacts.getCategorisations().add(categorisation); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(CATEGORISATION_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeMapWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeMapWriterTest.java new file mode 100644 index 0000000..f0c048d --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeMapWriterTest.java @@ -0,0 +1,52 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.CATEGORY_SCHEME_MAP_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeMapImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class CategorySchemeMapWriterTest extends BaseXmlWriterTest { + + @Test + void writeCategorySchemeMap() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + CategorySchemeMapWriter categorySchemeMapWriter = createCategorySchemeMapWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(categorySchemeMapWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + CategorySchemeMapImpl categorySchemeMap = MaintainableArtifactsTestUtils.buildCategorySchemeMap(); + artefacts.getCategorySchemeMaps().add(categorySchemeMap); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(CATEGORY_SCHEME_MAP_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeWriterTest.java new file mode 100644 index 0000000..80beee8 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CategorySchemeWriterTest.java @@ -0,0 +1,50 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.CATEGORY_SCHEME_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorySchemeImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class CategorySchemeWriterTest extends BaseXmlWriterTest { + + @Test + void writeCategoryScheme() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + CategorySchemeWriter categorySchemeWriter = createCategorySchemeWriter(); + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(categorySchemeWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + CategorySchemeImpl categoryScheme = MaintainableArtifactsTestUtils.buildCategoryScheme(); + artefacts.getCategorySchemes().add(categoryScheme); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(CATEGORY_SCHEME_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CodelistWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CodelistWriterTest.java new file mode 100644 index 0000000..a896dd2 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/CodelistWriterTest.java @@ -0,0 +1,52 @@ +package com.epam.jsdmx.xml30.structure.writer; + + +import static com.epam.jsdmx.xml30.structure.TestUtils.CODELIST_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class CodelistWriterTest extends BaseXmlWriterTest { + + @Test + void writeCodelist() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + CodelistWriter codeListWriter = createCodelistWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(codeListWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + CodelistImpl codelist = MaintainableArtifactsTestUtils.buildCodeList(); + artefacts.getCodelists().add(codelist); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(CODELIST_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeMapWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeMapWriterTest.java new file mode 100644 index 0000000..a37d22a --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeMapWriterTest.java @@ -0,0 +1,52 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.CONCEPT_SCHEME_MAP_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeMapImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class ConceptSchemeMapWriterTest extends BaseXmlWriterTest { + + @Test + void writeConceptSchemeMap() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + ConceptSchemeMapWriter conceptSchemeMapWriter = createConceptSchemeMapWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(conceptSchemeMapWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + ConceptSchemeMapImpl conceptSchemeMap = MaintainableArtifactsTestUtils.buildConceptSchemeMap(); + artefacts.getConceptSchemeMaps().add(conceptSchemeMap); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(CONCEPT_SCHEME_MAP_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeWriterTest.java new file mode 100644 index 0000000..79787cb --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ConceptSchemeWriterTest.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.xml30.structure.writer; + + +import static com.epam.jsdmx.xml30.structure.TestUtils.CONCEPT_SCHEME_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class ConceptSchemeWriterTest extends BaseXmlWriterTest { + + @Test + void writeConceptScheme() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + ConceptSchemeWriter conceptSchemeWriter = createConceptSchemeWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(conceptSchemeWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + ConceptSchemeImpl conceptScheme = MaintainableArtifactsTestUtils.buildConceptScheme(); + artefacts.getConceptSchemes().add(conceptScheme); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(CONCEPT_SCHEME_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataConstraintWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataConstraintWriterTest.java new file mode 100644 index 0000000..c128c83 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataConstraintWriterTest.java @@ -0,0 +1,87 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.DATA_CONSTRAINTS_EMPTY_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.DATA_CONSTRAINTS_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraintImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReleaseCalendarImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class DataConstraintWriterTest extends BaseXmlWriterTest { + + @Test + void writeDataConstraint() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + DataConstraintWriter dataConstraintWriter = createDataConstraintWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(dataConstraintWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + DataConstraint dataConstraint = MaintainableArtifactsTestUtils.buildDataConstraint(); + artefacts.getDataConstraints().add(dataConstraint); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(DATA_CONSTRAINTS_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } + + @Test + void writeEmptyDataConstraint() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + DataConstraintWriter dataConstraintWriter = createDataConstraintWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(dataConstraintWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + DataConstraintImpl dataConstraint = MaintainableArtifactsTestUtils.buildDataConstraint(); + dataConstraint.setDataContentKeys(List.of()); + dataConstraint.setCubeRegions(List.of()); + dataConstraint.setReleaseCalendar(new ReleaseCalendarImpl()); + artefacts.getDataConstraints().add(dataConstraint); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(DATA_CONSTRAINTS_EMPTY_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataConsumerSchemeWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataConsumerSchemeWriterTest.java new file mode 100644 index 0000000..1769158 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataConsumerSchemeWriterTest.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.DATA_CONSUMER_SCHEME_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConsumerSchemeImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class DataConsumerSchemeWriterTest extends BaseXmlWriterTest { + + @Test + void writeDataConsumerScheme() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + DataConsumerSchemeWriter dataConsumerSchemeWriter = createDataConsumerSchemeWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(dataConsumerSchemeWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + DataConsumerSchemeImpl consumerScheme = MaintainableArtifactsTestUtils.buildDataConsumerScheme(); + artefacts.getDataConsumerSchemes().add(consumerScheme); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(DATA_CONSUMER_SCHEME_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } + +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataProviderSchemeWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataProviderSchemeWriterTest.java new file mode 100644 index 0000000..a4ce8c7 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataProviderSchemeWriterTest.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.DATA_PROVIDER_SCHEME_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataProviderSchemeImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class DataProviderSchemeWriterTest extends BaseXmlWriterTest { + + @Test + void writeDataProviderScheme() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + DataProviderSchemeWriter dataProviderSchemeWriter = createDataProviderSchemeWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(dataProviderSchemeWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + DataProviderSchemeImpl dataProviderScheme = MaintainableArtifactsTestUtils.buildDataProviderScheme(); + artefacts.getDataProviderSchemes().add(dataProviderScheme); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(DATA_PROVIDER_SCHEME_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } + +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataStructureDefinitionWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataStructureDefinitionWriterTest.java new file mode 100644 index 0000000..db0a4bb --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataStructureDefinitionWriterTest.java @@ -0,0 +1,58 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.DSD_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataAttributeRef; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class DataStructureDefinitionWriterTest extends BaseXmlWriterTest { + + @Test + void writeDsd() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + DataStructureDefinitionWriter dataStructureDefinitionWriter = createDataStructureDefinitionWriter(); + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(dataStructureDefinitionWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + DataStructureDefinitionImpl dataStructureDefinition = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + dataStructureDefinition.setAttributeDescriptor(MaintainableArtifactsTestUtils.fillAttributeDescriptor()); + dataStructureDefinition.setDimensionDescriptor(MaintainableArtifactsTestUtils.fillDimensionDescriptor()); + dataStructureDefinition.setMeasureDescriptor(MaintainableArtifactsTestUtils.fillMeasureDescriptor()); + dataStructureDefinition.setGroupDimensionDescriptor(MaintainableArtifactsTestUtils.fillListGroupDimensionDescriptor()); + List attributeRefs = dataStructureDefinition.getAttributeDescriptor().getMetadataAttributes(); + List refs = List.of(attributeRefs.get(0), attributeRefs.get(1)); + dataStructureDefinition.getAttributeDescriptor().setMetadataAttributes(refs); + InputStream resourceAsStream = this.getClass().getResourceAsStream(DSD_XML); + artefacts.getDataStructures().add(dataStructureDefinition); + xmlStructureWriter.write(artefacts); + + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataflowWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataflowWriterTest.java new file mode 100644 index 0000000..ef3f751 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/DataflowWriterTest.java @@ -0,0 +1,52 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.DATAFLOW_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class DataflowWriterTest extends BaseXmlWriterTest { + + @Test + void writeDataflow() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + DataflowWriter dataflowWriter = createDataflowWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(dataflowWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + DataflowImpl dataflow = MaintainableArtifactsTestUtils.buildDataFlow(); + artefacts.getDataflows().add(dataflow); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(DATAFLOW_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/GeoGridCodelistWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/GeoGridCodelistWriterTest.java new file mode 100644 index 0000000..e357dc7 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/GeoGridCodelistWriterTest.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.xml30.structure.writer; + + +import static com.epam.jsdmx.xml30.structure.TestUtils.GEOGRID_CODELIST_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeoGridCodelist; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class GeoGridCodelistWriterTest extends BaseXmlWriterTest { + + @Test + void writeGeoGridCodelist() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + GeoGridCodelistWriter codeListWriter = createGeoGridCodelistWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(codeListWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + GeoGridCodelist codelist = MaintainableArtifactsTestUtils.buildGeoGridCodelist(); + artefacts.getGeoGridCodelists().add(codelist); + xmlStructureWriter.write(artefacts); + System.out.println(actual); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(GEOGRID_CODELIST_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/GeographicCodelistWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/GeographicCodelistWriterTest.java new file mode 100644 index 0000000..e9d7f01 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/GeographicCodelistWriterTest.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.xml30.structure.writer; + + +import static com.epam.jsdmx.xml30.structure.TestUtils.GEOGRAPHICAL_CODELIST_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.GeographicCodelist; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class GeographicCodelistWriterTest extends BaseXmlWriterTest { + + @Test + void writeCodelist() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + GeographicCodelistWriter codeListWriter = createGeographicCodelistWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(codeListWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + GeographicCodelist codelist = MaintainableArtifactsTestUtils.buildGeographicCodelist(); + artefacts.getGeographicCodelists().add(codelist); + xmlStructureWriter.write(artefacts); + System.out.println(actual); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(GEOGRAPHICAL_CODELIST_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/HierarchyAssociationWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/HierarchyAssociationWriterTest.java new file mode 100644 index 0000000..85e5277 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/HierarchyAssociationWriterTest.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.HIERARCHY_ASSOCIATION_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyAssociation; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class HierarchyAssociationWriterTest extends BaseXmlWriterTest { + + @Test + void writeHierarchyAssociation() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + HierarchyAssociationWriter hierarchyAssociationWriter = createHierarchyAssociationWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = + new XmlStructureWriter( + actual, + List.of(hierarchyAssociationWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + HierarchyAssociation hierarchyAssociation = MaintainableArtifactsTestUtils.buildHierarchyAssociation(); + artefacts.getHierarchyAssociations().add(hierarchyAssociation); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(HIERARCHY_ASSOCIATION_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/HierarchyWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/HierarchyWriterTest.java new file mode 100644 index 0000000..ab62d0b --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/HierarchyWriterTest.java @@ -0,0 +1,83 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.HIERARCHIES_NAMES_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.HIERARCHIES_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyImpl; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class HierarchyWriterTest extends BaseXmlWriterTest { + + @Test + void writeHierarchy() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + HierarchyWriter hierarchyWriter = createHierarchyWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = + new XmlStructureWriter( + actual, + List.of(hierarchyWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + HierarchyImpl hierarchy = MaintainableArtifactsTestUtils.buildHierarchy(); + artefacts.getHierarchies().add(hierarchy); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(HIERARCHIES_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } + + @Test + void writeHierarchyWithNull() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + HierarchyWriter hierarchyWriter = createHierarchyWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = + new XmlStructureWriter(actual, List.of(hierarchyWriter), new HeaderWriter(defaultHeaderProvider), false); + + //when + Artefacts artefacts = new ArtefactsImpl(); + HierarchyImpl hierarchy = MaintainableArtifactsTestUtils.buildHierarchy(); + InternationalString name = hierarchy.getName(); + name.add("it", null); + artefacts.getHierarchies().add(hierarchy); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(HIERARCHIES_NAMES_XML); + System.out.println(actual); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataConstraintWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataConstraintWriterTest.java new file mode 100644 index 0000000..31044d8 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataConstraintWriterTest.java @@ -0,0 +1,52 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataConstraintImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml30.structure.TestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class MetadataConstraintWriterTest extends BaseXmlWriterTest { + + @Test + void writeMetadataConstraint() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + MetadataConstraintWriter metadataConstraintWriter = createMetadataConstraintWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(metadataConstraintWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + MetadataConstraintImpl metadataConstraint = MaintainableArtifactsTestUtils.buildMetadataConstraint(false); + artefacts.getMetadataConstraints().add(metadataConstraint); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(TestUtils.METADATA_CONSTRAINTS_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataProviderSchemeWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataProviderSchemeWriterTest.java new file mode 100644 index 0000000..acd0a63 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataProviderSchemeWriterTest.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.METADATA_PROVIDER_SCHEME_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProviderScheme; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class MetadataProviderSchemeWriterTest extends BaseXmlWriterTest { + + @Test + void writeMetadataProviderScheme() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + MetadataProviderSchemeWriter metadataProviderSchemeWriter = createMetadataProviderSchemeWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(metadataProviderSchemeWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + MetadataProviderScheme metadataProviderScheme = MaintainableArtifactsTestUtils.buildMetadataProviderScheme(); + artefacts.getMetadataProviderSchemes().add(metadataProviderScheme); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(METADATA_PROVIDER_SCHEME_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } + +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataProvisionAgreementWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataProvisionAgreementWriterTest.java new file mode 100644 index 0000000..ebf7548 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataProvisionAgreementWriterTest.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.METADATA_PROVISION_AGREEMENT_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataProvisionAgreement; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class MetadataProvisionAgreementWriterTest extends BaseXmlWriterTest { + + @Test + void writeMetadataProvisionAgreement() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + MetadataProvisionAgreementWriter metadataProvisionAgreementWriter = createMetadataProvisionAgreementWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(metadataProvisionAgreementWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + MetadataProvisionAgreement metadataProviderScheme = MaintainableArtifactsTestUtils.buildMetadataProvisionAgreement(); + artefacts.getMetadataProvisionAgreements().add(metadataProviderScheme); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(METADATA_PROVISION_AGREEMENT_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } + +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataStructureDefinitionWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataStructureDefinitionWriterTest.java new file mode 100644 index 0000000..348bdaf --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataStructureDefinitionWriterTest.java @@ -0,0 +1,52 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.M_STRUCTURE_DEFINITION_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinitionImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class MetadataStructureDefinitionWriterTest extends BaseXmlWriterTest { + + @Test + void writeMDsd() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + MetadataStructureDefinitionWriter metadataStructureDefinitionWriter = createMetadataStructureDefinitionWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(metadataStructureDefinitionWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + MetadataStructureDefinitionImpl dataStructureDefinition = MaintainableArtifactsTestUtils.buildMetadataStructureDefinition(); + artefacts.getMetadataStructureDefinitions().add(dataStructureDefinition); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(M_STRUCTURE_DEFINITION_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataflowWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataflowWriterTest.java new file mode 100644 index 0000000..f8b19f5 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/MetadataflowWriterTest.java @@ -0,0 +1,51 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.METADATAFLOW_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataflowImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class MetadataflowWriterTest extends BaseXmlWriterTest { + + @Test + void writeMetaDataflow() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + MetadataflowWriter metadataflowWriter = createMetadataflowWriter(); + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(metadataflowWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + MetadataflowImpl dataflow = MaintainableArtifactsTestUtils.buildMetadataFlow(); + artefacts.getMetadataflows().add(dataflow); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(METADATAFLOW_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/OrganisationSchemeMapWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/OrganisationSchemeMapWriterTest.java new file mode 100644 index 0000000..b2fff11 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/OrganisationSchemeMapWriterTest.java @@ -0,0 +1,52 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.ORGANISATION_SCHEME_MAP_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationSchemeMap; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class OrganisationSchemeMapWriterTest extends BaseXmlWriterTest { + + @Test + void writeCategorySchemeMap() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + OrganisationSchemeMapWriter organisationSchemeMapWriter = createOrganisationSchemeMapWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(organisationSchemeMapWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + OrganisationSchemeMap organisationSchemeMap = MaintainableArtifactsTestUtils.buildOrganisationSchemeMap(); + artefacts.getOrganisationSchemeMaps().add(organisationSchemeMap); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(ORGANISATION_SCHEME_MAP_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/OrganisationUnitSchemeWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/OrganisationUnitSchemeWriterTest.java new file mode 100644 index 0000000..b90acd3 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/OrganisationUnitSchemeWriterTest.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.OrganisationUnitScheme; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml30.structure.TestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class OrganisationUnitSchemeWriterTest extends BaseXmlWriterTest { + + @Test + void writeOrganisationUnitScheme() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + OrganisationUnitSchemeWriter organisationUnitSchemeWriter = createOrganisationUnitSchemeWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(organisationUnitSchemeWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + OrganisationUnitScheme organisationUnitScheme = MaintainableArtifactsTestUtils.buildOrganisationUnitScheme(); + artefacts.getOrganisationUnitSchemes().add(organisationUnitScheme); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(TestUtils.ORGANISATION_UNIT_SCHEME_XML); + assert resourceAsStream != null; + + System.out.println(actual); + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ProcessWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ProcessWriterTest.java new file mode 100644 index 0000000..fed7121 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ProcessWriterTest.java @@ -0,0 +1,52 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.Process; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; +import com.epam.jsdmx.xml30.structure.TestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class ProcessWriterTest extends BaseXmlWriterTest { + + @Test + void writeProcess() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + ProcessWriter processWriter = createProcessWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(processWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + Process process = MaintainableArtifactsTestUtils.buildProcess(); + artefacts.getProcesses().add(process); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(TestUtils.PROCESS_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ProvisionAgreementWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ProvisionAgreementWriterTest.java new file mode 100644 index 0000000..7df6ff3 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ProvisionAgreementWriterTest.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils.buildProvisionAgreement; +import static com.epam.jsdmx.xml30.structure.TestUtils.PROVISION_AGREEMENT_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.ProvisionAgreement; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class ProvisionAgreementWriterTest extends BaseXmlWriterTest { + + @Test + void writeProvisionAgreement() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + ProvisionAgreementWriter provisionAgreementWriter = createProvisionAgreementWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(provisionAgreementWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + ProvisionAgreement provisionAgreement = buildProvisionAgreement(); + artefacts.getProvisionAgreements().add(provisionAgreement); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(PROVISION_AGREEMENT_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } + +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyMapWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyMapWriterTest.java new file mode 100644 index 0000000..3702227 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyMapWriterTest.java @@ -0,0 +1,52 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils.buildReportingTaxonomyMap; +import static com.epam.jsdmx.xml30.structure.TestUtils.REPORTING_TAXONOMY_MAP_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomyMap; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class ReportingTaxonomyMapWriterTest extends BaseXmlWriterTest { + + @Test + void writeReportingTaxonomyMap() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + ReportingTaxonomyMapWriter reportingTaxonomyMapWriter = createReportingTaxonomyMapWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(reportingTaxonomyMapWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + ReportingTaxonomyMap reportingTaxonomyMap = buildReportingTaxonomyMap(); + artefacts.getReportingTaxonomyMaps().add(reportingTaxonomyMap); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(REPORTING_TAXONOMY_MAP_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyWriterTest.java new file mode 100644 index 0000000..c3c72b6 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ReportingTaxonomyWriterTest.java @@ -0,0 +1,53 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils.buildReportingTaxonomy; +import static com.epam.jsdmx.xml30.structure.TestUtils.REPORTING_TAXONOMY_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.ReportingTaxonomy; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class ReportingTaxonomyWriterTest extends BaseXmlWriterTest { + + + @Test + void writeReportingTaxonomy() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + ReportingTaxonomyWriter reportingTaxonomyWriter = createReportingTaxonomyWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(reportingTaxonomyWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + ReportingTaxonomy reportingTaxonomy = buildReportingTaxonomy(); + artefacts.getReportingTaxonomies().add(reportingTaxonomy); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(REPORTING_TAXONOMY_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/RepresentationMapWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/RepresentationMapWriterTest.java new file mode 100644 index 0000000..cdaf9fa --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/RepresentationMapWriterTest.java @@ -0,0 +1,52 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.REPRESENTATION_MAP_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class RepresentationMapWriterTest extends BaseXmlWriterTest { + + @Test + void writeRepresentationMap() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + // root elements + RepresentationMapWriter representationMapWriter = createRepresentationMapWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(representationMapWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + RepresentationMapImpl representationMap = MaintainableArtifactsTestUtils.buildRepresentationMap(); + artefacts.getRepresentationMaps().add(representationMap); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(REPRESENTATION_MAP_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/StructureMapWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/StructureMapWriterTest.java new file mode 100644 index 0000000..04450a0 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/StructureMapWriterTest.java @@ -0,0 +1,52 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.STRUCTURE_MAP_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureMapImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class StructureMapWriterTest extends BaseXmlWriterTest { + + @Test + void writeStructureMap() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + // root elements + StructureMapWriter structureMapWriter = createStructureMapWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(structureMapWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + StructureMapImpl structureMap = MaintainableArtifactsTestUtils.buildStructureMap(); + artefacts.getStructureMaps().add(structureMap); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(STRUCTURE_MAP_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ValueListWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ValueListWriterTest.java new file mode 100644 index 0000000..b4af36c --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/ValueListWriterTest.java @@ -0,0 +1,52 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils.buildValueList; +import static com.epam.jsdmx.xml30.structure.TestUtils.VALUE_LIST_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.ValueList; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class ValueListWriterTest extends BaseXmlWriterTest { + + @Test + void writeValueList() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + + ValueListWriter valueListWriter = createValueListWriter(); + + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of(valueListWriter), + headerWriter, + false + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + ValueList valueList = buildValueList(); + artefacts.getValueLists().add(valueList); + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(VALUE_LIST_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/XmlStructureWriterTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/XmlStructureWriterTest.java new file mode 100644 index 0000000..0b2736c --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/XmlStructureWriterTest.java @@ -0,0 +1,109 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.ALL_XML; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.ArtefactsImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategorisationImpl; +import com.epam.jsdmx.infomodel.sdmx30.CategoryScheme; +import com.epam.jsdmx.infomodel.sdmx30.CodelistImpl; +import com.epam.jsdmx.infomodel.sdmx30.ConceptSchemeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataConstraint; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.HierarchyImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.MetadataflowImpl; +import com.epam.jsdmx.infomodel.sdmx30.RepresentationMapImpl; +import com.epam.jsdmx.infomodel.sdmx30.StructureMapImpl; +import com.epam.jsdmx.xml30.structure.MaintainableArtifactsTestUtils; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +class XmlStructureWriterTest extends BaseXmlWriterTest { + + @Test + void writeAll() throws IOException, SAXException { + //given + XMLUnit.setIgnoreWhitespace(true); + // root elements + ByteArrayOutputStream actual = new ByteArrayOutputStream(); + XmlStructureWriter xmlStructureWriter = new XmlStructureWriter( + actual, + List.of( + createCategorisationWriter(), + createConceptSchemeWriter(), + createCodelistWriter(), + createCategorySchemeWriter(), + createDataflowWriter(), + createDataStructureDefinitionWriter(), + createMetadataflowWriter(), + createMetadataStructureDefinitionWriter(), + createHierarchyWriter(), + createRepresentationMapWriter(), + createStructureMapWriter(), + createDataConstraintWriter() + ), + headerWriter, + true + ); + + //when + Artefacts artefacts = new ArtefactsImpl(); + + ConceptSchemeImpl conceptScheme = MaintainableArtifactsTestUtils.buildConceptScheme(); + artefacts.getConceptSchemes().add(conceptScheme); + + CategoryScheme categoryScheme = MaintainableArtifactsTestUtils.buildCategoryScheme(); + artefacts.getCategorySchemes().add(categoryScheme); + + CategorisationImpl categorisation = MaintainableArtifactsTestUtils.buildCategorisation(); + artefacts.getCategorisations().add(categorisation); + + CodelistImpl codelist = MaintainableArtifactsTestUtils.buildCodeList(); + artefacts.getCodelists().add(codelist); + + DataflowImpl dataflow = MaintainableArtifactsTestUtils.buildDataFlow(); + artefacts.getDataflows().add(dataflow); + + MetadataflowImpl metadataflow = MaintainableArtifactsTestUtils.buildMetadataFlow(); + artefacts.getMetadataflows().add(metadataflow); + + DataStructureDefinitionImpl dataStructureDefinition = MaintainableArtifactsTestUtils.buildDataStructureDefinition(); + artefacts.getDataStructures().add(dataStructureDefinition); + + MetadataStructureDefinitionImpl metadataStructureDefinition = MaintainableArtifactsTestUtils.buildMetadataStructureDefinition(); + artefacts.getMetadataStructureDefinitions().add(metadataStructureDefinition); + + HierarchyImpl hierarchy = MaintainableArtifactsTestUtils.buildHierarchy(); + artefacts.getHierarchies().add(hierarchy); + + RepresentationMapImpl representationMap = MaintainableArtifactsTestUtils.buildRepresentationMap(); + artefacts.getRepresentationMaps().add(representationMap); + + StructureMapImpl structureMap = MaintainableArtifactsTestUtils.buildStructureMap(); + artefacts.getStructureMaps().add(structureMap); + + DataConstraint dataConstraint = MaintainableArtifactsTestUtils.buildDataConstraint(); + artefacts.getDataConstraints().add(dataConstraint); + + xmlStructureWriter.write(artefacts); + + InputStream resourceAsStream = this.getClass().getResourceAsStream(ALL_XML); + assert resourceAsStream != null; + + //then + String expected = IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8); + assertXMLEqual(expected, actual.toString()); + } +} diff --git a/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/XsdToXmlTest.java b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/XsdToXmlTest.java new file mode 100644 index 0000000..4da1313 --- /dev/null +++ b/sdmx-ml30/src/test/java/com/epam/jsdmx/xml30/structure/writer/XsdToXmlTest.java @@ -0,0 +1,83 @@ +package com.epam.jsdmx.xml30.structure.writer; + +import static com.epam.jsdmx.xml30.structure.TestUtils.AGENCY_SCHEME_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.ALL_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.CATEGORISATION_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.CATEGORY_SCHEME_MAP_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.CATEGORY_SCHEME_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.CODELIST_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.CONCEPT_SCHEME_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.DATAFLOW_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.DATA_CONSTRAINTS_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.DATA_CONSUMER_SCHEME_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.DATA_PROVIDER_SCHEME_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.DSD_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.HIERARCHIES_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.HIERARCHY_ASSOCIATION_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.METADATAFLOW_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.METADATA_CONSTRAINTS_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.METADATA_PROVIDER_SCHEME_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.METADATA_PROVISION_AGREEMENT_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.M_STRUCTURE_DEFINITION_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.ORGANISATION_SCHEME_MAP_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.ORGANISATION_UNIT_SCHEME_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.PROCESS_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.PROVISION_AGREEMENT_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.REPORTING_TAXONOMY_MAP_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.REPORTING_TAXONOMY_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.REPRESENTATION_MAP_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.STRUCTURE_MAP_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.VALUE_LIST_XML; +import static com.epam.jsdmx.xml30.structure.TestUtils.validateXMLSchema; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Objects; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.util.ResourceUtils; + +class XsdToXmlTest { + + public static final String XML_XSD_SCHEMAS_SDMXMESSAGE_XSD = "/xml/xsd/schemas/SDMXMessage.xsd"; + + @ParameterizedTest + @ValueSource(strings = { + CODELIST_XML, + HIERARCHIES_XML, + CONCEPT_SCHEME_XML, + CATEGORISATION_XML, + DSD_XML, + DATAFLOW_XML, + M_STRUCTURE_DEFINITION_XML, + METADATAFLOW_XML, + REPRESENTATION_MAP_XML, + STRUCTURE_MAP_XML, + CATEGORY_SCHEME_XML, + AGENCY_SCHEME_XML, + CATEGORY_SCHEME_MAP_XML, + CONCEPT_SCHEME_XML, + ALL_XML, + DATA_CONSUMER_SCHEME_XML, + DATA_PROVIDER_SCHEME_XML, + METADATA_PROVIDER_SCHEME_XML, + HIERARCHY_ASSOCIATION_XML, + METADATA_CONSTRAINTS_XML, + DATA_CONSTRAINTS_XML, + METADATA_PROVISION_AGREEMENT_XML, + ORGANISATION_SCHEME_MAP_XML, + PROCESS_XML, + PROVISION_AGREEMENT_XML, + REPORTING_TAXONOMY_XML, + REPORTING_TAXONOMY_MAP_XML, + VALUE_LIST_XML, + ORGANISATION_UNIT_SCHEME_XML + }) + void xmlToXsd(String path) throws FileNotFoundException { + File fileXsd = ResourceUtils.getFile(Objects.requireNonNull(this.getClass().getResource(XML_XSD_SCHEMAS_SDMXMESSAGE_XSD))); + File fileXml = ResourceUtils.getFile(Objects.requireNonNull(this.getClass().getResource(path))); + Assertions.assertTrue(validateXMLSchema(fileXsd, fileXml)); + } +} diff --git a/sdmx-ml30/src/test/resources/xml/agency-scheme.xml b/sdmx-ml30/src/test/resources/xml/agency-scheme.xml new file mode 100644 index 0000000..f4d6fb6 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/agency-scheme.xml @@ -0,0 +1,85 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + + Agency + Agency + + AG_1 + IT + writing + ecrire + 9458673082 + somedatafax + X400 + test@email.com + + + AG_2 + IT + writing + ecrire + 9458673082 + somedatafax2 + X400 + test@email.com + + + + Agency + Agency + + AG_1 + IT + writing + ecrire + 9458673082 + somedatafax + X400 + test@email.com + + + AG_2 + IT + writing + ecrire + 9458673082 + somedatafax2 + X400 + test@email.com + + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/all.xml b/sdmx-ml30/src/test/resources/xml/all.xml new file mode 100644 index 0000000..601d215 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/all.xml @@ -0,0 +1,360 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.categoryscheme.Categorisation=IMF:ARTEFACT(1.2).CAT_SOURCE + urn:sdmx:org.sdmx.infomodel.categoryscheme.Category=IMF:ARTEFACT(1.2).CAT_TARGET + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + Country + + + + sent + sentinel descr + + + + + QHB + Schema + Conn + + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + code 1 + code 1 desc + CODE2 + + + code 2 + code 2 desc + + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1) + + mem1 + + + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1) + + mem2 + + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + Category1 + description category 1 + + + + + + Category2 + description category2 + + + Category3 + description category3 + + + + Category4 + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2) + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2) + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=IMF:METADATA(1.0.0) + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2) + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.3) + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DIM + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0) + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DIM + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0) + + + + + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + hierarchy name + hierarchy desc + + + + + + + urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1 + Lev1 + + + urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL2 + Lev2 + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_SOURCE(1.0) + DateTime + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_TARGET(1.0) + + mappedValue + targetValue1 + targetValue2 + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0) + urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0) + + CompMapEpochS + CompMapEpochT + Frequency_dim + FR3 + + + CompMapDPS + CompMapDPT + Frequency_dim + FR1 + FR2 + + + CODE_3 + 2022-11 + + + CODE_1 + 2022-11 + + + CODE_2 + 2022-11 + + + CompMapRepS + CompMapRepT + urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2) + + + STRUC_ID + value + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP + + + Periodicity + Offset + Tolerance + + + + + Value + + + MEM + local + + + + 2028 + + + + + + + + + + MEM + + + MEM + local + + + + 2022 + 2022 + + + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/categorisation.xml b/sdmx-ml30/src/test/resources/xml/categorisation.xml new file mode 100644 index 0000000..876e52c --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/categorisation.xml @@ -0,0 +1,35 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.categoryscheme.Categorisation=IMF:ARTEFACT(1.2).CAT_SOURCE + urn:sdmx:org.sdmx.infomodel.categoryscheme.Category=IMF:ARTEFACT(1.2).CAT_TARGET + + + + diff --git a/sdmx-ml30/src/test/resources/xml/category-scheme-map.xml b/sdmx-ml30/src/test/resources/xml/category-scheme-map.xml new file mode 100644 index 0000000..411fa47 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/category-scheme-map.xml @@ -0,0 +1,49 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:CatScheme(1.0) + urn:sdmx:org.sdmx.infomodel.categoryscheme.CategoryScheme=IMF:CatScheme(1.1) + + + + + S-1 + IM-1 + + + + + + S-2 + IM-2 + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/category-scheme.xml b/sdmx-ml30/src/test/resources/xml/category-scheme.xml new file mode 100644 index 0000000..06efe7b --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/category-scheme.xml @@ -0,0 +1,55 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + Category1 + description category 1 + + + + + + Category2 + description category2 + + + Category3 + description category3 + + + + Category4 + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/codelist.xml b/sdmx-ml30/src/test/resources/xml/codelist.xml new file mode 100644 index 0000000..afa21d8 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/codelist.xml @@ -0,0 +1,54 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + code 1 + code 1 desc + CODE2 + + + code 2 + code 2 desc + + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1) + + mem1 + + + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1) + + mem2 + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/concept-scheme-map.xml b/sdmx-ml30/src/test/resources/xml/concept-scheme-map.xml new file mode 100644 index 0000000..3d371a8 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/concept-scheme-map.xml @@ -0,0 +1,49 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ConScheme(1.0) + urn:sdmx:org.sdmx.infomodel.conceptscheme.ConceptScheme=IMF:ConScheme(1.1) + + + + + S-1 + IM-1 + + + + + + S-2 + IM-2 + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/concept-scheme.xml b/sdmx-ml30/src/test/resources/xml/concept-scheme.xml new file mode 100644 index 0000000..a69579d --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/concept-scheme.xml @@ -0,0 +1,49 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + Country + + + + sent + sentinel descr + + + + + QHB + Schema + Conn + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/concept-scheme_with_enum_format.xml b/sdmx-ml30/src/test/resources/xml/concept-scheme_with_enum_format.xml new file mode 100644 index 0000000..699dd72 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/concept-scheme_with_enum_format.xml @@ -0,0 +1,46 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + Country + ACCURACY + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=ESTAT:CL_NA_STO(1.15) + + + + QHB + Schema + Conn + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/data-constraints-empty.xml b/sdmx-ml30/src/test/resources/xml/data-constraints-empty.xml new file mode 100644 index 0000000..96ce2ec --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/data-constraints-empty.xml @@ -0,0 +1,37 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/data-constraints-skip-validTo.xml b/sdmx-ml30/src/test/resources/xml/data-constraints-skip-validTo.xml new file mode 100644 index 0000000..340a0c8 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/data-constraints-skip-validTo.xml @@ -0,0 +1,46 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP + + + Periodicity + Offset + Tolerance + + + + MEM + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/data-constraints.xml b/sdmx-ml30/src/test/resources/xml/data-constraints.xml new file mode 100644 index 0000000..325bca7 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/data-constraints.xml @@ -0,0 +1,75 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP + + + Periodicity + Offset + Tolerance + + + + + Value + + + MEM + local + + + + 2028 + + + + + + + + + + MEM + + + MEM + local + + + + 2022 + 2022 + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/data-consumer-scheme.xml b/sdmx-ml30/src/test/resources/xml/data-consumer-scheme.xml new file mode 100644 index 0000000..6091952 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/data-consumer-scheme.xml @@ -0,0 +1,57 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + Data Consumer + Data Consumer description + + AG_1 + IT + writing + ecrire + 9458673082 + somedatafax + X400 + test@email.com + + + AG_2 + IT + writing + ecrire + 9458673082 + somedatafax2 + X400 + test@email.com + + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/data-provider-scheme.xml b/sdmx-ml30/src/test/resources/xml/data-provider-scheme.xml new file mode 100644 index 0000000..0fc1aa6 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/data-provider-scheme.xml @@ -0,0 +1,61 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + Val + + + D_P + + AG_1 + IT + writing + ecrire + 9458673082 + somedatafax + X400 + test@email.com + + + AG_2 + IT + writing + ecrire + 9458673082 + somedatafax2 + X400 + test@email.com + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/dataflow.xml b/sdmx-ml30/src/test/resources/xml/dataflow.xml new file mode 100644 index 0000000..392a27e --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataflow.xml @@ -0,0 +1,34 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2) + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_atts_obs.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_atts_obs.xml new file mode 100644 index 0000000..0096e76 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_atts_obs.xml @@ -0,0 +1,27 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_atts_series.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_atts_series.xml new file mode 100644 index 0000000..5cfdc0c --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_atts_series.xml @@ -0,0 +1,29 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_dataset_atts.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_dataset_atts.xml new file mode 100644 index 0000000..6256f01 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_dataset_atts.xml @@ -0,0 +1,35 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + attribute2 + attribute3 + + + + + dataset_attr + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups.xml new file mode 100644 index 0000000..5bce68c --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups.xml @@ -0,0 +1,28 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups_meta.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups_meta.xml new file mode 100644 index 0000000..b1c91a4 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups_meta.xml @@ -0,0 +1,35 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + + attr + + + + + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups_obs.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups_obs.xml new file mode 100644 index 0000000..fff62a6 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups_obs.xml @@ -0,0 +1,30 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups_series.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups_series.xml new file mode 100644 index 0000000..117af73 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_groups_series.xml @@ -0,0 +1,32 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta.xml new file mode 100644 index 0000000..84af22a --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta.xml @@ -0,0 +1,52 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + + dataset_attr + + + + + + gr_attr + + + + + + + att_series + + + + + + att_obs + att_obs2 + + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta2.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta2.xml new file mode 100644 index 0000000..84af22a --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta2.xml @@ -0,0 +1,52 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + + dataset_attr + + + + + + gr_attr + + + + + + + att_series + + + + + + att_obs + att_obs2 + + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta_flat.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta_flat.xml new file mode 100644 index 0000000..4116632 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta_flat.xml @@ -0,0 +1,41 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + + dataset_attr + + + + + + att_series + + + att_obs + att_obs2 + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta_multi.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta_multi.xml new file mode 100644 index 0000000..d164cf8 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_meta_multi.xml @@ -0,0 +1,42 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + dataset_attr + dataset_attr2 + + + + + mult_value_1 + mult_value_2 + + + + meta1 + meta2 + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_multiling_atts.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_multiling_atts.xml new file mode 100644 index 0000000..2415b47 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_multiling_atts.xml @@ -0,0 +1,58 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + + + english + french + + + + + + + english + french + + + + + + english + french + + + + + + + + english + french + + + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_multiling_atts_obs.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_multiling_atts_obs.xml new file mode 100644 index 0000000..626c2ec --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_multiling_atts_obs.xml @@ -0,0 +1,40 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + + attribute + + + + english + french + + + english + french + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_obs.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_obs.xml new file mode 100644 index 0000000..47b5be4 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_obs.xml @@ -0,0 +1,22 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + HeaderTest + HeaderTest + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_series.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_series.xml new file mode 100644 index 0000000..3970d37 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_series.xml @@ -0,0 +1,31 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_series_and_obs.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_series_and_obs.xml new file mode 100644 index 0000000..3244ec2 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_series_and_obs.xml @@ -0,0 +1,38 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + + mult1 + + + + + + + mult_value_1 + mult_value_2 + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_series_multi.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_series_multi.xml new file mode 100644 index 0000000..66bf374 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_data_query_series_multi.xml @@ -0,0 +1,37 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + mult_value_1 + mult_value_2 + + + + + + mult_value_3 + mult_value_4 + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_dataset.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_dataset.xml new file mode 100644 index 0000000..2866cf9 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_dataset.xml @@ -0,0 +1,36 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + + + + + + + + + dataset_attr + + + + diff --git a/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_dataset_flat.xml b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_dataset_flat.xml new file mode 100644 index 0000000..66f8af7 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dataquery/xml_3.0_dataset_flat.xml @@ -0,0 +1,37 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=agnc1:id1(1.0) + + + + + + + + + + + + + + dataset_attr + + + + diff --git a/sdmx-ml30/src/test/resources/xml/dsd.xml b/sdmx-ml30/src/test/resources/xml/dsd.xml new file mode 100644 index 0000000..acd85fe --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dsd.xml @@ -0,0 +1,111 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0) + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE + + + + + + + + + val + + + val + + + + DIM1 + + + TIME_PERIOD + + + + + DIM1 + + + + + REFERENCE-1 + + + + + + REFERENCE-2 + + dim1 + dim2 + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE + + GroupKey + + + MO + + + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE + + + + urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2) + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/dsd_with_df_attr_relationship.xml b/sdmx-ml30/src/test/resources/xml/dsd_with_df_attr_relationship.xml new file mode 100644 index 0000000..1772c3e --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dsd_with_df_attr_relationship.xml @@ -0,0 +1,97 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0) + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE + + + + + + + + META_1 + + + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE + + + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=ESTAT:CS_NA(1.17.0).CONF_STATUS + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_CONF_STATUS(1.3) + + + + + + + OBS_VALUE + + + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE + + + + urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2) + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/dsd_with_enumFormat.xml b/sdmx-ml30/src/test/resources/xml/dsd_with_enumFormat.xml new file mode 100644 index 0000000..ffa483b --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/dsd_with_enumFormat.xml @@ -0,0 +1,113 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DATE_VALUE + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0) + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:TIME_DIMENSION(1.6.1).DATE_VALUE + + + + + + + + + val + + + val + + + + DIM1 + + + TIME_PERIOD + + + + + DIM1 + + + + + REFERENCE-1 + + + + + + REFERENCE-2 + + dim1 + dim2 + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS_COLLECTION_SCHEME(1.5.1).DATE_VALUE + + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE + + GroupKey + + + MO + + + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:MEASURE(1.5.2).DATE_VALUE + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER(1.5.1).DATE_VALUE + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:ADVANCED_RELEASE_CALANDER_DIAGNOSTICS(1.5.2).DATE_VALUE + + + + urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=QUANTHUB:ECOFIN_DSD(1.2) + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/geographical-codelist.xml b/sdmx-ml30/src/test/resources/xml/geographical-codelist.xml new file mode 100644 index 0000000..8688cdd --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/geographical-codelist.xml @@ -0,0 +1,55 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + code 1 + code 1 desc + CODE2 + + + code 2 + code 2 desc + + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1) + + mem1 + + + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1) + + mem2 + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/geogrid-codelist.xml b/sdmx-ml30/src/test/resources/xml/geogrid-codelist.xml new file mode 100644 index 0000000..bf6e98f --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/geogrid-codelist.xml @@ -0,0 +1,57 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + code 1 + code 1 desc + CODE2 + Value1 + + + code 2 + code 2 desc + Value2 + + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1) + + mem1 + + + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=SDMX:CL_AGE(2.1.1) + + mem2 + + + DEFINITION + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/hierarchy-association.xml b/sdmx-ml30/src/test/resources/xml/hierarchy-association.xml new file mode 100644 index 0000000..52953d6 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/hierarchy-association.xml @@ -0,0 +1,36 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.codelist.Hierarchy=IMF:ARTEFACT(1.2) + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.3) + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=IMF:ARTEFACT(1.2) + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/hierarchy.xml b/sdmx-ml30/src/test/resources/xml/hierarchy.xml new file mode 100644 index 0000000..1dcc9f5 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/hierarchy.xml @@ -0,0 +1,49 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + hierarchy name + hierarchy desc + + + + + + + urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1 + Lev1 + + + urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL2 + Lev2 + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/hierarchy_names.xml b/sdmx-ml30/src/test/resources/xml/hierarchy_names.xml new file mode 100644 index 0000000..f35c168 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/hierarchy_names.xml @@ -0,0 +1,50 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + + artefact + Some artefact + + hierarchy name + hierarchy desc + + + + + + + urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL1 + Lev1 + + + urn:sdmx:org.sdmx.infomodel.codelist.Code=SDMX:CL_AGE(2.1.1).CL2 + Lev2 + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/mdsd.xml b/sdmx-ml30/src/test/resources/xml/mdsd.xml new file mode 100644 index 0000000..81ae3e9 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/mdsd.xml @@ -0,0 +1,52 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DIM + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0) + + + urn:sdmx:org.sdmx.infomodel.conceptscheme.Concept=IMF:DIMENSION(1.6.1).DIM + + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST(1.0) + + + + + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/metadata-constraints.xml b/sdmx-ml30/src/test/resources/xml/metadata-constraints.xml new file mode 100644 index 0000000..ed5238a --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/metadata-constraints.xml @@ -0,0 +1,52 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + urn:sdmx:org.sdmx.infomodel.base.MetadataProvider=IMF:METADATA_PROVIDERS(1.0).PR + + + Periodicity + Offset + Tolerance + + + + MEM + local + + + + 2023 + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/metadata-provider-scheme.xml b/sdmx-ml30/src/test/resources/xml/metadata-provider-scheme.xml new file mode 100644 index 0000000..b2c4dd8 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/metadata-provider-scheme.xml @@ -0,0 +1,61 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + Val + + + MD_P + + AG_1 + IT + writing + ecrire + 9458673082 + somedatafax + X400 + test@email.com + + + AG_2 + IT + writing + ecrire + 9458673082 + somedatafax2 + X400 + test@email.com + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/metadata-provision-agreement.xml b/sdmx-ml30/src/test/resources/xml/metadata-provision-agreement.xml new file mode 100644 index 0000000..3118936 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/metadata-provision-agreement.xml @@ -0,0 +1,35 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=IMF:ARTEFACT(1.2) + urn:sdmx:org.sdmx.infomodel.base.MetadataProvider=IMF:METADATA_PROVIDERS(1.0).PR + + + + diff --git a/sdmx-ml30/src/test/resources/xml/metadata-set.xml b/sdmx-ml30/src/test/resources/xml/metadata-set.xml new file mode 100644 index 0000000..3c8d365 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/metadata-set.xml @@ -0,0 +1,41 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.metadatastructure.Metadataflow=EPM:MetadataSet(1.8) + urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataSet=EPM:MetadataSetTar(1.8) + + + + + someVal + + someVal2 + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/metadataflow.xml b/sdmx-ml30/src/test/resources/xml/metadataflow.xml new file mode 100644 index 0000000..663676e --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/metadataflow.xml @@ -0,0 +1,36 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.metadatastructure.MetadataStructure=IMF:METADATA(1.0.0) + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.2) + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=QUANTHUB:ECOFIN_DSD(1.3) + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/organisation-scheme-map.xml b/sdmx-ml30/src/test/resources/xml/organisation-scheme-map.xml new file mode 100644 index 0000000..069ea7b --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/organisation-scheme-map.xml @@ -0,0 +1,49 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.base.AgencyScheme=SDMX:AGENCIES(1.0) + urn:sdmx:org.sdmx.infomodel.base.AgencyScheme=SDMX:AGENCIES(1.0) + + + + + S-1 + IM-1 + + + + + + S-2 + IM-2 + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/organisation-unit-scheme.xml b/sdmx-ml30/src/test/resources/xml/organisation-unit-scheme.xml new file mode 100644 index 0000000..e968238 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/organisation-unit-scheme.xml @@ -0,0 +1,64 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + OrganisationUnit + OrganisationUnit description + + AG_1 + IT + writing + ecrire + 9458673082 + somedatafax + X400 + test@email.com + + + AG_2 + IT + writing + ecrire + 9458673082 + somedatafax2 + X400 + test@email.com + + + + OrganisationUnit + OrgUnit + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/process.xml b/sdmx-ml30/src/test/resources/xml/process.xml new file mode 100644 index 0000000..85782b8 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/process.xml @@ -0,0 +1,69 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + ProcessStep + ProcessStep description + + + + + urn:sdmx:org.sdmx.infomodel.process.ProcessStep=IMF:Artefact(1.0) + + + + + + urn:sdmx:org.sdmx.infomodel.process.ProcessStep=IMF:Artefact(1.0) + + + + + + Computation Description + + + ST + Doo + + + + + + ProcessStepChild + + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/provision-agreement.xml b/sdmx-ml30/src/test/resources/xml/provision-agreement.xml new file mode 100644 index 0000000..e2bcc65 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/provision-agreement.xml @@ -0,0 +1,35 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=IMF:ARTEFACT(1.2) + urn:sdmx:org.sdmx.infomodel.base.DataProvider=IMF:DATA_PROVIDERS(1.0).DP + + + + diff --git a/sdmx-ml30/src/test/resources/xml/reporting-taxonomy-map.xml b/sdmx-ml30/src/test/resources/xml/reporting-taxonomy-map.xml new file mode 100644 index 0000000..37291b1 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/reporting-taxonomy-map.xml @@ -0,0 +1,49 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.categoryscheme.ReportingTaxonomy=SDMX:REP_SOURCE(1.0) + urn:sdmx:org.sdmx.infomodel.categoryscheme.ReportingTaxonomy=SDMX:REP_TARGET(1.0) + + + + + S-1 + IM-1 + + + + + + S-2 + IM-2 + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/reporting-taxonomy.xml b/sdmx-ml30/src/test/resources/xml/reporting-taxonomy.xml new file mode 100644 index 0000000..c58e16b --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/reporting-taxonomy.xml @@ -0,0 +1,51 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + ReportingCat + ReportingCat description + + + + + ReportingCat2 + ReportingCat2 description + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=EPM:DataS2(3.0) + urn:sdmx:org.sdmx.infomodel.datastructure.DataStructure=EPM:DataS1(3.0) + + urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataS2(3.0) + urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataS1(3.0) + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/representation_map.xml b/sdmx-ml30/src/test/resources/xml/representation_map.xml new file mode 100644 index 0000000..b629b7e --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/representation_map.xml @@ -0,0 +1,41 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_SOURCE(1.0) + DateTime + urn:sdmx:org.sdmx.infomodel.codelist.Codelist=IMF:CODELIST_TARGET(1.0) + + mappedValue + targetValue1 + targetValue2 + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/structure_map.xml b/sdmx-ml30/src/test/resources/xml/structure_map.xml new file mode 100644 index 0000000..bedeaa9 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/structure_map.xml @@ -0,0 +1,69 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFSource(3.0) + urn:sdmx:org.sdmx.infomodel.datastructure.Dataflow=EPM:DataFTarget(3.0) + + CompMapEpochS + CompMapEpochT + Frequency_dim + FR3 + + + CompMapDPS + CompMapDPT + Frequency_dim + FR1 + FR2 + + + CODE_3 + 2022-11 + + + CODE_1 + 2022-11 + + + CODE_2 + 2022-11 + + + CompMapRepS + CompMapRepT + urn:sdmx:org.sdmx.infomodel.structuremapping.RepresentationMap=IMF:ARTEFACT(1.2) + + + STRUC_ID + value + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/valuelist.xml b/sdmx-ml30/src/test/resources/xml/valuelist.xml new file mode 100644 index 0000000..f5329b2 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/valuelist.xml @@ -0,0 +1,49 @@ + + + + HED1 + true + 2023-04-17T10:11:16Z + + HeaderTest + + + HeaderTest + + + + + + + + type1 + text + + + Maintanable artefact + artefact + Some artefact + + + + + value + val + it is value + c'est val + + + + + + smth + smth description + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXCommon.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXCommon.xsd new file mode 100644 index 0000000..b8d3352 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXCommon.xsd @@ -0,0 +1,1349 @@ + + + + + + + + + SDMX Common Namespace Module + The common namespace module contains common constructs that are used by constructs in other namespaces. + + + + + ValueType is an abstract class that is the basis for any component value that cannot be simply represented as a space-normalized value (e.g. in an XML attribute). Although its content is mixed, it should be restricted so that only character data or the Text or Structured text is used. See StringValueType, IntValueType, ObserverationalTimeValueType, TextValueType, and StructuredTextValueType for details. + + + + + + + + + + BooleanValueType is a refinement of SimpleValueType limiting the content to be a boolean. + + + + + + + + + + + + + StringValueType is a refinement of SimpleValueType limiting the content to be a string. This can be further refined with facets, patterns, etc. + + + + + + + + + + + + + IntValueType is a refinement of SimpleValueType limiting the content to be an integer. This can be further refined ranges, etc. + + + + + + + + + + + + + DoubleValueType is a refinement of SimpleValueType limiting the content to be a double. This can be further refined ranges, etc. + + + + + + + + + + + + + ObservationalTimePeriodValueType is a refinement of SimpleValueType limiting the content to be an observational time period. + + + + + + + + + + + + + TextValueType is a restriction of ValueType that allows mutliple Text elements to expressed a text value in multiple languages. The content of this should be restricted in its use to only allow a langue code (xml:lang) to be used once within an element of this type. + + + + + + + + + + + + + StructuredTextValueType is a restriction of ValueType that allows mutliple StructuredText (XHTML mixed content) elements to expressed a text value in multiple languages. The content of this should be restricted in its use to only allow a langue code (xml:lang) to be used once within an element of this type. + + + + + + + + + + + + + TextType provides for a set of language-specific alternates to be provided for any human-readable constructs in the instance. + + + + + + The xml:lang attribute specifies a language code for the text. If not supplied, the default language is assumed to be English. + + + + + + + + + Name is a reusable element, used for providing a human-readable name for an object. + + + + + + Description is a reusable element, used for providing a longer human-readable description of an object. + + + + + + Text is a reusable element, used for providing a language specific text value for general purposes (i.e. not for a name or description). + + + + + + StructuredText is a reusable element, used for providing a language specific text value structured as XHTML. + + + + + + StatusMessageType describes the structure of an error or warning message. A message contains the text of the message, as well as an optional language indicator and an optional code. + + + + + Text contains the text of the message, in parallel language values. + + + + + + The code attribute holds an optional code identifying the underlying error that generated the message. This should be used if parallel language descriptions of the error are supplied, to distinguish which of the multiple error messages are for the same underlying error. + + + + + + + EmptyType is an empty complex type for elements where the presence of the tag indicates all that is necessary. + + + + + + CodedStatusMessageType describes the structure of an error or warning message which required a code. + + + + + + + + + + + + + + AnnotableType is an abstract base type used for all annotable artefacts. Any type that provides for annotations should extend this type. + + + + + + + + + Annotations is a reusable element the provides for a collection of annotations. It has been made global so that restrictions of types that extend AnnotatableType may reference it. + + + + + + AnnotationsType provides for a list of annotations to be attached to data and structure messages. + + + + + + + + + AnnotationType provides for non-documentation notes and annotations to be embedded in data and structure messages. It provides optional fields for providing a title, a type description, a URI, and the text of the annotation. + + + + + AnnotationTitle provides a title for the annotation. + + + + + AnnotationType is used to distinguish between annotations designed to support various uses. The types are not enumerated, as these can be specified by the user or creator of the annotations. The definitions and use of annotation types should be documented by their creator. + + + + + AnnotationURL is a URI - typically a URL - which points to an external resource which may contain or supplement the annotation. These can be localised by indicating a language for the resource. If a language is not specified, the resource is assumed to not be localised. If a specific behavior is desired, an annotation type should be defined which specifies the use of this field more exactly. + + + + + AnnotationText holds a language-specific string containing the text of the annotation. + + + + + AnnotationValue holds a non-localised value for the annotation. + + + + + + The id attribute provides a non-standard identification of an annotation. It can be used to disambiguate annotations. + + + + + + + AnnotationURLType defines an external resource. These can indicate localisation by specifying a language for the resource. + + + + + + Indicates the language of the resources at the URL, if it is localised. If this does not exist, the resource is not localised. + + + + + + + + + Allows for the linking of other resources to identifiable objects. For example, if there is reference metadata associated with a structure, a link to the meatadata report can be dynamically inserted in the structure metadata. + + + + + + + The type of object that is being linked to. + + + + + The url of the object being linked. + + + + + A SDMX registry urn of the object being linked (if applicable). + + + + + The type of link (e.g. PDF, text, HTML, reference metadata). + + + + + + + IdentifiableType is an abstract base type for all identifiable objects. + + + + + + + + + The id is the identifier for the object. + + + + + The urn attribute holds a valid SDMX Registry URN (see SDMX Registry Specification for details). + + + + + The uri attribute holds a URI that contains a link to a resource with additional information about the object, such as a web page. This uri is not a SDMX message. + + + + + + + + + NameableType is an abstract base type for all nameable objects. + + + + + + + Name provides for a human-readable name for the object. This may be provided in multiple, parallel language-equivalent forms. + + + + + Description provides for a longer human-readable description of the object. This may be provided in multiple, parallel language-equivalent forms. + + + + + + + + + + VersionableType is an abstract base type for all versionable objects. + + + + + + This version attribute holds a version number (see common:VersionType definition for details). If not supplied, artefact is considered to be un-versioned. + + + + + The validFrom attribute provides the inclusive start date for providing supplemental validity information about the version. + + + + + The validTo attribute provides the inclusive end date for providing supplemental validity information about the version. + + + + + + + + + MaintainableBaseType is an abstract type that only serves the purpose of forming the base for the actual MaintainableType. The purpose of this type is to restrict the VersionableType to require the id attribute. + + + + + + + + + + + + + + + + + + MaintainableType is an abstract base type for all maintainable objects. + + + + + + The agencyID must be provided, and identifies the maintenance agency of the object. + + + + + The isExternalReference attribute, if true, indicates that the actual object is not defined the corresponding element, rather its full details are defined elsewhere - indicated by either the registryURL, the repositoryURL, or the structureURL. The purpose of this is so that each structure message does not have to redefine object that are already defined elsewhere. If the isExternalReference attribute is not set, then it is assumed to be false, and the object should contain the full definition of its contents. If more than one of the registryURL, the repositoryURL, and the structureURL are supplied, then the application processing the object can choose the method it finds best suited to retrieve the details of the object. + + + + + + + + + + The SetAttributeGroup defines a common set of attributes for use in data and reference metadata sets. + + + + The action attribute indicates whether the file is appending, replacing, or deleting. + + + + + The reportingBeginDate indicates the inclusive start time of the data reported in the data or metadata set. + + + + + The reportingEndDate indicates the inclusive end time of the data reported in the data or metadata set. + + + + + The publicationYear holds the ISO 8601 four-digit year. + + + + + The publicationPeriod specifies the period of publication of the data or metadata in terms of whatever provisioning agreements might be in force (i.e., "Q1 2005" if that is the time of publication for a data set published on a quarterly basis). + + + + + + + + The serviceURL attribute indicates the URL of an SDMX SOAP web service from which the details of the object can be retrieved. Note that this can be a registry or and SDMX structural metadata repository, as they both implement that same web service interface. + + + + + The structureURL attribute indicates the URL of a SDMX-ML structure message (in the same version as the source document) in which the externally referenced object is contained. Note that this may be a URL of an SDMX RESTful web service which will return the referenced object. + + + + + + + AlphaNumericType is a reusable simple type that allows for only mixed-case alphabetical and numeric characters. + + + + + + + + + AlphaType is a reusable simple type that allows for only mixed-case alphabetical characters. This is derived from the AlphaNumericType. + + + + + + + + + NumericType is a reusable simple type that allows for only numeric characters. This is not to be confused with an integer, as this may be used to numeric strings which have leading zeros. These leading zeros are not ignored. This is derived from the AlphaNumericType. + + + + + + + + + ObservationalTimePeriodType specifies a distinct time period or point in time in SDMX. The time period can either be a Gregorian calendar period, a standard reporting period, a distinct point in time, or a time range with a specific date and duration. + + + + + + + StandardTimePeriodType defines the set of standard time periods in SDMX. This includes the reporting time periods and the basic date type (i.e. the calendar time periods and the dateTime format). + + + + + + + BasicTimePeriodType contains the basic dates and calendar periods. It is a combination of the Gregorian time periods and the date time type.. + + + + + + + GregorianTimePeriodType defines the set of standard calendar periods in SDMX. + + + + + + + ReportingTimePeriodType defines standard reporting periods in SDMX, which are all in relation to the start day (day-month) of a reporting year which is specified in the specialized reporting year start day attribute. If the reporting year start day is not defined, a day of January 1 is assumed. The reporting year must be epxressed as the year at the beginning of the period. Therfore, if the reproting year runs from April to March, any given reporting year is expressed as the year for April. The general format of a report period can be described as [year]-[period][time zone]?, where the type of period is designated with a single character followed by a number representing the period. Note that all periods allow for an optional time zone offset. See the details of each member type for the specifics of its format. + + + + + + + BaseReportPeriodType is a simple type which frames the general pattern of a reporting period for validation purposes. This regular expression is only a general validation which is meant to validate the following structure [year]-[period][time zone]?. This type is meant to be derived from for further validation. + + + + + + + + + ReportPeriodValidTimeZoneType is a derivation of the BaseReportPeriodType which validates that the time zone provided in the base type is valid. The base type will have provided basic validation already. The patterns below validate that the time zone is "Z" or that it is between -14:00 and +14:00, or that there is no time zone provided. This type is meant to be derived from for further validation. + + + + + + + + + + + ReportingYearType defines a time period of 1 year (P1Y) in relation to a reporting year which has a start day (day-month) specified in the specialized reporting year start day attribute. In the absence of a start day for the reporting year, a day of January 1 is assumed. In this case a reporting year will coincide with a calendar year. The format of a reporting year is YYYY-A1 (e.g. 2000-A1). Note that the period value of 1 is fixed. + + + + + + + + + ReportingSemesterType defines a time period of 6 months (P6M) in relation to a reporting year which has a start day (day-month) specified in the specialized reporting year start day attribute. In the absence of a start day for the reporting year, a day of January 1 is assumed. The format of a reporting semester is YYYY-Ss (e.g. 2000-S1), where s is either 1 or 2. + + + + + + + + + ReportingTrimesterType defines a time period of 4 months (P4M) in relation to a reporting year which has a start day (day-month) specified in the specialized reporting year start day attribute. In the absence of a start day for the reporting year, a day of January 1 is assumed. The format of a reporting trimester is YYYY-Tt (e.g. 2000-T1), where s is either 1, 2, or 3. + + + + + + + + + ReportingQuarterType defines a time period of 3 months (P3M) in relation to a reporting year which has a start day (day-month) specified in the specialized reporting year start day attribute. In the absence of a start day for the reporting year, a day of January 1 is assumed. The format of a reporting quarter is YYYY-Qq (e.g. 2000-Q1), where q is a value between 1 and 4. + + + + + + + + + ReportingMonthType defines a time period of 1 month (P1M) in relation to a reporting year which has a start day (day-month) specified in the specialized reporting year start day attribute. In the absence of a start day for the reporting year, a day of January 1 is assumed. In this case a reporting month will coincide with a calendar month. The format of a reporting month is YYYY-Mmm (e.g. 2000-M01), where mm is a two digit month (i.e. 01-12). + + + + + + + + + ReportingWeekType defines a time period of 7 days (P7D) in relation to a reporting year which has a start day (day-month) specified in the specialized reporting year start day attribute. A standard reporting week is based on the ISO 8601 defintion of a week date, in relation to the reporting period start day. The first week is defined as the week with the first Thursday on or after the reporting year start day. An equivalent definition is the week starting with the Monday nearest in time to the reporting year start day. There are other equivalent defintions, all of which should be adjusted based on the reporting year start day. In the absence of a start day for the reporting year, a day of January 1 is assumed. The format of a reporting week is YYYY-Www (e.g. 2000-W01), where mm is a two digit week (i.e. 01-53). + + + + + + + + + ReportingDayType defines a time period of 1 day (P1D) in relation to a reporting year which has a start day (day-month) specified in the specialized reporting year start day attribute. In the absence of a start day for the reporting year, a day of January 1 is assumed. The format of a reporting day is YYYY-Dddd (e.g. 2000-D001), where ddd is a three digit day (i.e. 001-366). + + + + + + + + + BaseTimeRangeType is a simple type which frames the general pattern for a time range in SDMX. A time range pattern is generally described as [xs:date or xs:dateTime]\[xs:duration], where the referenced types are defined by XML Schema. This type is meant to be derived from for further validation. + + + + + + + + + RangeValidMonthDayType is a derivation of the BaseTimeRangeType which validates that the day provided is valid for the month, without regard to leap years. The base type will have provided basic validation already. The patterns below validate that there are up to 29 days in February, up to 30 days in April, June, September, and November and up to 31 days in January, March, May, July, August, October, and December. This type is meant to be derived from for further validation. + + + + + + + + + + + RangeValidLeapYearType is a derivation of the RangeValidMonthDayType which validates that a date of February 29 occurs in a valid leap year (i.e. if the year is divisible 4 and not by 100, unless it is also divisible by 400). This type is meant to be derived from for further validation. + + + + + + + + + + + RangeValidTimeType is a derivation of the RangeValidLeapYearType which validates that the time (if provided) is validly formatted. The base type will have provided basic validation already. The patterns below validate that the time falls between 00:00:00 and 24:00:00. Note that as the XML dateTime type does, seconds are required. It is also permissible to have fractions of seconds, but only within the boundaries of the range specified. This type is meant to be derived from for further validation. + + + + + + + + + + RangeValidMonthDayType is a derivation of the RangeValidTimeType which validates that the time zone provided in the base type is valid. The base type will have provided basic validation already. The patterns below validate that the time zone is "Z" or that it is between -14:00 and +14:00, or that there is no time zone provided. This type is meant to be derived from for further validation. + + + + + + + + + + + TimeRangeValidDateDurationType is an abstract derivation of the RangeValidTimeType which validates that duration provided is generally valid, up to the time component. + + + + + + + + + TimeRangeType defines the structure of a time range in SDMX. The pattern of a time range can be generally described as [start date]\[duration], where start date is an date or dateTime type as defined in XML Schema and duration is a time duration as defined in XML Schema. Note that it is permissible for a time zone offset to be provided on the date or date time. + + + + + + + + + + TimezoneType defines the pattern for a time zone. An offset of -14:00 to +14:00 or Z can be specified. + + + + + + + + + + Specifies the inclusive start and end times. + + + + The startTime attributes contains the inclusive start date for the reference period. + + + + + The endTime attributes contains the inclusive end date for the reference period. + + + + + + + OccurenceType is used to express the maximum occurrence of an object. It combines an integer, equal or greater than 1, and the literal text, "unbounded", for objects which have no upper limit on its occurrence. + + + + + + + MaxOccursNumberType is a base type used to restrict an integer to be greater than 1, for the purpose of expressing the maximum number of occurrences of an object. + + + + + + + + + UnboundedCodeType provides single textual value of "unbounded", for use in OccurentType. + + + + + Object has no upper limit on occurrences. + + + + + + + + ActionType provides a list of actions, describing the intention of the data transmission from the sender's side. Each action provided at the data or metadata set level applies to the entire data set for which it is given. Note that the actions indicated in the Message Header are optional, and used to summarize specific actions indicated with this data type for all registry interactions. The "Informational" value is used when the message contains information in response to a query, rather than being used to invoke a maintenance activity. + + + + + Append - this is an incremental update for an existing data/metadata set or the provision of new data or documentation (attribute values) formerly absent. If any of the supplied data or metadata is already present, it will not replace that data or metadata. This corresponds to the "Update" value found in version 1.0 of the SDMX Technical Standards. + + + + + Replace - data/metadata is to be replaced, and may also include additional data/metadata to be appended. The replacement occurs at the level of the observation - that is, it is not possible to replace an entire series. + + + + + Delete - data/metadata is to be deleted. Deletion occurs at the lowest level object. For instance, if a delete data message contains a series with no observations, then the entire series will be deleted. If the series contains observations, then only those observations specified will be deleted. The same basic concept applies for attributes. If a series or observation in a delete message contains attributes, then only those attributes will be deleted. + + + + + Informational - data/metadata is being exchanged for informational purposes only, and not meant to update a system. + + + + + + + + WildCardValueType is a single value code list, used to include the '%' character - indicating that an entire field is wild carded. + + + + + Indicates a wild card value. + + + + + + + + QueryableDataSourceType describes a data source which is accepts an standard SDMX Query message and responds appropriately. + + + + + DataURL contains the URL of the data source. + + + + + WSDLURL provides the location of a WSDL instance on the internet which describes the queryable data source. + + + + + WADLURL provides the location of a WADL instance on the internet which describes the REST protocol of the queryable data source. + + + + + + The isRESTDatasource attribute indicates, if true, that the queryable data source is accessible via the REST protocol. + + + + + The isWebServiceDatasource attribute indicates, if true, that the queryable data source is accessible via Web Services protocols. + + + + + + + XHTMLType allows for mixed content of text and XHTML tags. When using this type, one will have to provide a reference to the XHTML schema, since the processing of the tags within this type is strict, meaning that they are validated against the XHTML schema provided. + + + + + + + + + + + + PayloadStructureType is an abstract base type used to define the structural information for data or metadata sets. A reference to the structure is provided (either explicitly or through a reference to a structure usage). + + + + + + ProvisionAgreement references a provision agreement which the data or metadata is reported against. + + + + + StructureUsage references a flow which the data or metadata is reported against. + + + + + Structure references the structure which defines the structure of the data or metadata set. + + + + + + + The structureID attribute uniquely identifies the structure for the purpose of referencing it from the payload. This is only used in structure specific formats. Although it is required, it is only useful when more than one data set is present in the message. + + + + + The schemaURL attribute provides a location from which the structure specific schema can be located. + + + + + The namespace attribute is used to provide the namespace for structure-specific formats. By communicating this information in the header, it is possible to generate the structure specific schema while processing the message. + + + + + The dimensionAtObservation is used to reference the dimension at the observation level for data messages. This can also be given the explicit value of "AllDimensions" which denotes that the cross sectional data is in the flat format. + + + + + The explicitMeasures indicates whether explicit measures are used in the cross sectional format. This is only applicable for the measure dimension as the dimension at the observation level or the flat structure. + + + + + + + + DataStructureType is an abstract base type the forms the basis for the structural information for a data set. + + + + + + + + ProvisionAgreement references a provision agreement which the data is reported against. + + + + + StructureUsage references a dataflow which the data is reported against. + + + + + Structure references the data structure definition which defines the structure of the data. + + + + + + + + + + + StructureSpecificDataStructureType defines the structural information for a structured data set. In addition to referencing the data structure or dataflow which defines the structure of the data, the namespace for the data structure specific schema as well as which dimension is used at the observation level must be provided. It is also necessary to state whether the format uses explicit measures, although this is technically only applicable is the dimension at the observation level is the measure dimension or the flat data format is used. + + + + + + + + + + + + + + + + + + + + MetadataStructureType is an abstract base type the forms the basis of the structural information for any metadata message. A reference to the metadata structure definition or a metadataflow must be provided. This can be used to determine the structure of the message. + + + + + + + + ProvisionAgreement references a provision agreement which the metadata is reported against. + + + + + StructureUsage references a metadataflow which the metadata is reported against. + + + + + Structure references the metadata structure definition which defines the structure of the metadata. + + + + + + + + + + + + + GenericMetadataStructureType defines the structural information for a generic metadata message. + + + + + + + + + + + + + + + + + + + + + + ExcludeRootType is a single enumerated value that indciates that child values should be included, but that the actual root should not. + + + + + + + + + ObservationDimensionType allows for the dimension at the observation level to be specified by either providing the dimension identifier or using the explicit value "AllDimensions". + + + + + + + ObsDimensionsCodeType is an enumeration containing the values "TimeDimension" and "AllDimensions" + + + + + AllDimensions notes that the cross sectional format shall be flat; that is all dimensions should be contained at the observation level. + + + + + TIME_PERIOD refers to the fixed identifier for the time dimension. + + + + + + + + DataTypeType provides an enumerated list of the types of data formats allowed as the for the representation of an object. + + + + + A string datatype corresponding to W3C XML Schema's xs:string datatype. + + + + + A string datatype which only allows for the simple aplhabetic charcter set of A-Z, a-z. + + + + + A string datatype which only allows for the simple alphabetic character set of A-Z, a-z plus the simple numeric character set of 0-9. + + + + + A string datatype which only allows for the simple numeric character set of 0-9. This format is not treated as an integer, and therefore can having leading zeros. + + + + + An integer datatype corresponding to W3C XML Schema's xs:integer datatype. + + + + + An integer datatype corresponding to W3C XML Schema's xs:int datatype. + + + + + A numeric datatype corresponding to W3C XML Schema's xs:long datatype. + + + + + A numeric datatype corresponding to W3C XML Schema's xs:short datatype. + + + + + A numeric datatype corresponding to W3C XML Schema's xs:decimal datatype. + + + + + A numeric datatype corresponding to W3C XML Schema's xs:float datatype. + + + + + A numeric datatype corresponding to W3C XML Schema's xs:double datatype. + + + + + A datatype corresponding to W3C XML Schema's xs:boolean datatype. + + + + + A datatype corresponding to W3C XML Schema's xs:anyURI datatype. + + + + + A simple incrementing Integer type. The isSequence facet must be set to true, and the interval facet must be set to "1". + + + + + This value indicates that the startValue and endValue attributes provide the inclusive boundaries of a numeric range of type xs:decimal. + + + + + This value indicates that the startValue and endValue attributes provide the exclusive boundaries of a numeric range, of type xs:decimal. + + + + + This value indicates that the value increments according to the value provided in the interval facet, and has a true value for the isSequence facet. + + + + + Observational time periods are the superset of all time periods in SDMX. It is the union of the standard time periods (i.e. Gregorian time periods, the reporting time periods, and date time) and a time range. + + + + + Standard time periods is a superset of distinct time period in SDMX. It is the union of the basic time periods (i.e. the Gregorian time periods and date time) and the reporting time periods. + + + + + BasicTimePeriod time periods is a superset of the Gregorian time periods and a date time. + + + + + Gregorian time periods correspond to calendar periods and are represented in ISO-8601 formats. This is the union of the year, year month, and date formats. + + + + + A Gregorian time period corresponding to W3C XML Schema's xs:gYear datatype, which is based on ISO-8601. + + + + + A time datatype corresponding to W3C XML Schema's xs:gYearMonth datatype, which is based on ISO-8601. + + + + + A time datatype corresponding to W3C XML Schema's xs:date datatype, which is based on ISO-8601. + + + + + Reporting time periods represent periods of a standard length within a reporting year, where to start of the year (defined as a month and day) must be defined elsewhere or it is assumed to be January 1. This is the union of the reporting year, semester, trimester, quarter, month, week, and day. + + + + + A reporting year represents a period of 1 year (P1Y) from the start date of the reporting year. This is expressed as using the SDMX specific ReportingYearType. + + + + + A reporting semester represents a period of 6 months (P6M) from the start date of the reporting year. This is expressed as using the SDMX specific ReportingSemesterType. + + + + + A reporting trimester represents a period of 4 months (P4M) from the start date of the reporting year. This is expressed as using the SDMX specific ReportingTrimesterType. + + + + + A reporting quarter represents a period of 3 months (P3M) from the start date of the reporting year. This is expressed as using the SDMX specific ReportingQuarterType. + + + + + A reporting month represents a period of 1 month (P1M) from the start date of the reporting year. This is expressed as using the SDMX specific ReportingMonthType. + + + + + A reporting week represents a period of 7 days (P7D) from the start date of the reporting year. This is expressed as using the SDMX specific ReportingWeekType. + + + + + A reporting day represents a period of 1 day (P1D) from the start date of the reporting year. This is expressed as using the SDMX specific ReportingDayType. + + + + + A time datatype corresponding to W3C XML Schema's xs:dateTime datatype. + + + + + TimeRange defines a time period by providing a distinct start (date or date time) and a duration. + + + + + A time datatype corresponding to W3C XML Schema's xs:gMonth datatype. + + + + + A time datatype corresponding to W3C XML Schema's xs:gMonthDay datatype. + + + + + A time datatype corresponding to W3C XML Schema's xs:gDay datatype. + + + + + A time datatype corresponding to W3C XML Schema's xs:time datatype. + + + + + A time datatype corresponding to W3C XML Schema's xs:duration datatype. + + + + + A string used to describe geographical features like points (e.g., locations of places, landmarks, buildings, etc.), lines (e.g., rivers, roads, streets, etc.), or areas (e.g., geographical regions, countries, islands, land lots, etc.). A mix of different features is possible too, e.g., combining polygons and geographical points to describe a country and the location of its capital. + + + + + This value indicates that the content of the component can contain XHTML markup. + + + + + This value indicates that the content of the component will be data key (a set of dimension references and values for the dimensions). + + + + + This value indicates that the content of the component will be complete reference (either URN or full set of reference fields) to an Identifiable object in the SDMX Information Model. + + + + + This value indicates that the content of the component will be reference to a data provider, which is actually a formal reference to a data provider and a data set identifier value. + + + + + + + + BasicComponentDataType provides an enumerated list of the types of characters allowed in the textType attribute for all non-target object components. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SimpleDataType restricts BasicComponentDataType to specify the allowable data types for a data structure definition component. The XHTML representation is removed as a possible type. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TimeDataType restricts SimpleDataType to specify the allowable data types for representing a time value. + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXCommonReferences.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXCommonReferences.xsd new file mode 100644 index 0000000..a01e6d7 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXCommonReferences.xsd @@ -0,0 +1,1631 @@ + + + + + + + SDMX Common References Module + The common references module contains common constructs that are used to reference objects. + + + + + + This is validates the first part of the URN (urn:sdmx.org.infomodel.<package>.<class=). It is intended to be further restricted. + + + + + + + + + This refines the prefix to make specific restrictions of package and class values. Note that only one of the patterns must match. It is intended to be further restricted. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This restricts the prefix and classes patterns to validate the agency part of the URN (=<agency_id>:). + + + + + + + + + This restricts the prefix and classes patterns to validate the agency part of a wildcarded URN reference (=<agency_id>:). + + + + + + + + + + This refines the prefix, classes, and agnecy patterns to validate the maintainable ID part of the URN (:<maintainable_id(<version_number>)). Note that it does not restrict the version part as it is intended to be further restricted. + + + + + + + + + This refines the prefix, classes, and agnecy patterns to validate the maintainable ID part of a wildcarded URN reference (:<maintainable_id(<version_number>)). Note that it does not restrict the version part as it is intended to be further restricted. + + + + + + + + + + This refines the prefix, classes, agency, and maintainable id patterns to validate the version number part of the URN ((<version_number)). It accounts for both legacy and semantic versioning, but not wildarding (for referencing). It is meant to be further refined, although all parts after this are optional. + + + + + + + + + + This refines the prefix, classes, agency, and maintainable id patterns to validate the version number part of a URN reference ((<version_number)). It accounts for both legacy and semantic versioning (including late binding). It is meant to be further refined, although all parts after this are optional. + + + + + + + + + + + + + This refines the prefix, classes, agency, and maintainable id patterns to validate the version number part of a wildcarded URN reference ((<version_number)). It accounts for both legacy and semantic versioning (including late binding). It is meant to be further refined, although all parts after this are optional. + + + + + + + + + + + + + + The completes the refinement of the prefix, classes, agency, maintainable id, and version number patterns to validate the last, and optional, nested component part of the URN (e.g. (<version_number>)<containerobject-id>.<object-id>*). The nested patterns provide a complete validation of the URN pattern. + + + + + + + + + The completes the refinement of the prefix, classes, agency, maintainable id, and version number patterns to validate the last, and optional, nested component part of a URN reference (e.g. (<version_number>)<containerobject-id>.<object-id>*). The nested patterns provide a complete validation of the URN pattern. + + + + + + + + + The completes the refinement of the prefix, classes, agency, maintainable id, and version number patterns to validate the last, and optional, nested component part of a wildcarded URN reference (e.g. (<version_number>)<containerobject-id>.<object-id>*). The nested patterns provide a complete validation of the URN pattern. + + + + + + + + + + Restricts the URN so that the pattern ends after the version part. + + + + + + + + + Restricts the URN reference so that the pattern ends after the version part. + + + + + + + + + Restricts the URN so that the pattern ends after the first component part. + + + + + + + + + Restricts the URN reference so that the pattern ends after the first component part. + + + + + + + + + + + Urn type for an agency. + + + + + + + + + Urn type for an agency scheme. + + + + + + + + + Urn type for a data consumer. + + + + + + + + + Urn type for a data consumer scheme. + + + + + + + + + Urn type for a data provider. + + + + + + + + + Urn type for a data provider scheme. + + + + + + + + + Urn type for a metadata provider. + + + + + + + + + Urn type for a metadata provider scheme. + + + + + + + + + Urn type for an organisation unit. + + + + + + + + + Urn type for an organisation unit scheme. + + + + + + + + + Urn type for a categorisation. + + + + + + + + + Urn type for a category. + + + + + + + + + Urn type for a category scheme. + + + + + + + + + Urn type for a reporting category. + + + + + + + + + Urn type for a reporting taxonomy. + + + + + + + + + Urn type for a code. + + + + + + + + + Urn type for a codelist. + + + + + + + + + Urn type for a hierarchical code. + + + + + + + + + Urn type for a hierarchy. + + + + + + + + + Urn type for a hierarchy association. + + + + + + + + + Urn type for a level. + + + + + + + + + Urn type for a value list. + + + + + + + + + Urn type for a concept. + + + + + + + + + Urn type for a concept scheme. + + + + + + + + + Urn type for an attribute descriptor. + + + + + + + + + Urn type for a data attribute. + + + + + + + + + Urn type for a dataflow. + + + + + + + + + Urn type for a data structure. + + + + + + + + + Urn type for a dimension. + + + + + + + + + Urn type for a dimension descriptor. + + + + + + + + + Urn type for a group dimension descriptor. + + + + + + + + + Urn type for a measure. + + + + + + + + + Urn type for a measure descriptor. + + + + + + + + + Urn type for a time dimension. + + + + + + + + + Urn type for a metadata attibute. + + + + + + + + + Urn type for a metadataflow. + + + + + + + + + Urn type for a metadata set. + + + + + + + + + Urn type for a metadata structure. + + + + + + + + + Urn type for a process. + + + + + + + + + Urn type for a process step. + + + + + + + + + Urn type for a transition. + + + + + + + + + Urn type for a data constraint. + + + + + + + + + Urn type for a metadata constraint. + + + + + + + + + Urn type for a metadata provision agreement. + + + + + + + + + Urn type for a provision agreement. + + + + + + + + + Urn type for a category scheme map. + + + + + + + + + Urn type for a concept scheme map. + + + + + + + + + Urn type for a date pattern map. + + + + + + + + + Urn type for a epoch map. + + + + + + + + + Urn type for a frequency format mapping. + + + + + + + + + Urn type for a organisation scheme map. + + + + + + + + + Urn type for a reporting taxonomy map. + + + + + + + + + Urn type for a representation map. + + + + + + + + + Urn type for a structure map. + + + + + + + + + Urn type for a custom type. + + + + + + + + + Urn type for a custom type scheme. + + + + + + + + + Urn type for a name personalisation. + + + + + + + + + Urn type for a name personalisation scheme. + + + + + + + + + Urn type for a ruleset. + + + + + + + + + Urn type for a ruleste scheme. + + + + + + + + + Urn type for a transformation. + + + + + + + + + Urn type for a transformation scheme. + + + + + + + + + Urn type for a user defined operator. + + + + + + + + + Urn type for a user defined operator scheme. + + + + + + + + + Urn type for a VTL mapping. + + + + + + + + + + + Urn type for a VTL mapping scheme. + + + + + + + + + + A reference type for a structure or structure usage. + + + + + + + + + + + + A reference type for structure usage. + + + + + + + + + + A reference type for a structure. + + + + + + + + + + A reference type for a codelist or value list. + + + + + + + + + + A reference type for any type of organisation scheme. + + + + + + + + + + + + + A reference type for any type of organisation. + + + + + + + + + + + + + A reference for any type of constraint. + + + + + + + + + + A reference type for an agency. + + + + + + + + + A reference type for an agency scheme. + + + + + + + + + A reference type for a data consumer. + + + + + + + + + A reference type for a data consumer scheme. + + + + + + + + + A reference type for a data provider. + + + + + + + + + A reference type for a data provider scheme. + + + + + + + + + A reference type for a metadata provider. + + + + + + + + + A reference type for a metadata provider scheme. + + + + + + + + + A reference type for an organisation unit. + + + + + + + + + A reference type for an organisation unit scheme. + + + + + + + + + A reference type for a categorisation. + + + + + + + + + A reference type for a category. + + + + + + + + + A reference type for a cateogry scheme. + + + + + + + + + A reference type for a reporting category. + + + + + + + + + A reference type for a reporting taxonomy. + + + + + + + + + A reference type for a code. + + + + + + + + + A reference type for a codelist. + + + + + + + + + A reference type for a hierarchical code. + + + + + + + + + A reference type for a hierarchy. + + + + + + + + + A reference type for a hierarchy association. + + + + + + + + + A reference type for a level. + + + + + + + + + A reference type for a value list. + + + + + + + + + A reference type for a concept. + + + + + + + + + A reference type for a concept scheme. + + + + + + + + + A reference type for an attribute descriptor. + + + + + + + + + A reference type for a data attribute. + + + + + + + + + A reference type for a dataflow. + + + + + + + + + A reference type for a data structure. + + + + + + + + + A reference type for a dimension. + + + + + + + + + A reference type for a dimension descriptor. + + + + + + + + + A reference type for a group dimension descriptor. + + + + + + + + + A reference type for a measure. + + + + + + + + + A reference type for a measure descriptor. + + + + + + + + + A reference type for a time dimension. + + + + + + + + + A reference type for a metadata attribute. + + + + + + + + + A reference type for a metadataflow. + + + + + + + + + A reference type for a metadata set. + + + + + + + + + A reference type for a metadata structure. + + + + + + + + + A reference type for a process. + + + + + + + + + A reference type for a process step. + + + + + + + + + A reference type for a transition. + + + + + + + + + A reference type for a data constraint. + + + + + + + + + A reference type for a metadata constraint. + + + + + + + + + A reference type for a metadata provision agreement. + + + + + + + + + A reference type for a provision agreement. + + + + + + + + + A reference type for a category scheme map. + + + + + + + + + A reference type for a concept scheme map. + + + + + + + + + A reference type for a date pattern map. + + + + + + + + + A reference type for an epoch map. + + + + + + + + + A reference type for a frequnecy format mapping. + + + + + + + + + A reference type for a organisation scheme map. + + + + + + + + + + A reference type for a reporting taxonomy map. + + + + + + + + + A reference type for a representation map. + + + + + + + + + A reference type for a structure map. + + + + + + + + + A reference type for a custom type. + + + + + + + + + A reference type for a custom type scheme. + + + + + + + + + A reference type for a name personalisation. + + + + + + + + + A reference type for a name personalisation scheme. + + + + + + + + + A reference type for a ruleset. + + + + + + + + + A reference type for a ruleset scheme. + + + + + + + + + A reference type for a transformation. + + + + + + + + + A reference type for a transformation scheme. + + + + + + + + + A reference type for a user defined operator. + + + + + + + + + A reference type for a user defined operator scheme. + + + + + + + + + A reference type for a VTL mapping. + + + + + + + + + + + A reference type for a VTL mapping scheme. + + + + + + + + + + VersionReferenceType defines the structure of version number in a reference. When semantic versioning is used, the major, minor, or patch version parts can be wildcarded using "+" as an extension. For example, 2+.3.1 means the currently latest available version >= 2.3.1 (even if not backwards compatible). Note that wildcarded semantic version references cannot be combined with version extended reference (e.g. 2.3+.1-draft is not permissable). Version-extended (e.g. 1.3.1-draft) and legacy version numbers (e.g. 1 or 1.0) are also supported. + + + + + + + SemanticVersionReferenceType is a simple type for referencing semantic version numbers. It allows for the wildcarding of only one the major, minor, or patch version parts using "+". + + + + + + + + + + + WildcardVersionType combines the VersionType and WildcardType to allow a reference to either a specific version of an object, or to wildcard the version in the reference by specifying the '*' value. + + + + + + + WildcardType is a single value code list, used to include the '*' character - indicating that the identification component is wildcarded. + + + + + Indicates that any value of the identifier component is allowed. + + + + + + + + + + NestedIDType is the least restrictive form of an identifier used throughout all SDMX-ML messages. It allows for a hierarchical identifier, with each portion separated by the '.' character. For the identifier portions, valid characters include A-Z, a-z, @, 0-9, _, -, $. + + + + + + + + + TwoLevelIDType defines an identifier with exactly two levels. + + + + + + + + + IDType provides a type which is used for restricting the characters in codes and IDs throughout all SDMX-ML messages. Valid characters include A-Z, a-z, @, 0-9, _, -, $. + + + + + + + + + NCNameIDType restricts the IDType, so that the id may be used to generate valid XML components. IDs created from this type conform to the W3C XML Schema NCNAME type, and therefore can be used as element or attribute names. + + + + + + + + + NestedNCNameIDType restricts the NestedIDType, so that the id may be used to generate valid XML components. IDs created from this type conform to the W3C XML Schema NCNAME type, and therefore can be used as element or attribute names. + + + + + + + + + SingleNCNameIDType restricts the NestedNCNameIDType to allow only one level. Note that this is the same pattern as the NCNameIDType, but can be used when the base type to be restricted is a nested NCNameIDType (where as the NCNameIDType could only restrict the IDType). + + + + + + + + + VersionType is used to communicate version information. Semantic versioning, based on 3 or 4 version parts (major.minor.patch[-extension]) is supported. The legency SDMX version format is also support. + + + + + + + SemanticVersionNumberType is a simple type for validating semantic version in the format (major.minor.patch[-extension]). + + + + + + + + + LegacyVersionNumberType describes the version number format previously supported in SDMX. The format is restricted to allow for simple incrementing and sorting of version number. The version consists of a set of maximum 2 numeric components, separated by the '.' character. When processing version, each numeric component (the number preceding and following any '.' character) should be parsed as an integer. Thus, a version of 1.3 and 1.03 would be equivalent, as both the '3' component and the '03' component would parse to an integer value of 3. + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecific.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecific.xsd new file mode 100644 index 0000000..fb1efd1 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXDataStructureSpecific.xsd @@ -0,0 +1,260 @@ + + + + + + + + SDMX Core Structure Specific Data Namespace Module + The core structure specific data namespace module provides the common framework to be used for all data structure definition-specific schemas for data exchange, update, and revisions. It is intended for bilateral use. This forms the basis for all sets of namespace modules created and maintained by those who create data structure definition-specific data schemas which are not maintained by SDMX. The data set defined here describes the structure of the data set in all structure specific data messages. Any structure specific data messages must derive the data set from this format. The entire structure declared for the is data set is abstract, meaning that instances will have to be based on types derived from these structures in schemas created based on the details data structure definition. + + + + + +

DataSetType is the abstract type which defines the base structure for any data structure definition specific data set. A derived data set type will be created that is specific to a data structure definition and the details of the organisation of the data (i.e. which dimension is the observation dimension). Data is organised into either a collection of series (grouped observations) or a collection of un-grouped observations. The derived data set type will restrict this choice to be either grouped or un-grouped observations. If this dimension is "AllDimensions" then the derived data set type must consist of a collection of un-grouped observations; otherwise the data set will contain a collection of series with the observations in the series disambiguated by the specified dimension at the observation level. This data set is capable of containing data (observed values) and/or documentation (data and metadata attribute values) and can be used for incremental updates and deletions (i.e. only the relevant updates or deletes are exchanged). It is assumed that each series or un-grouped observation will be distinct in its purpose. For example, if series contains both data and documentation, it assumed that each series will have a unique key. If the series contains only data or only documentation, then it is possible that another series with the same key might exist, but with not with the same purpose (i.e. to provide data or documentation) as the first series.

+ +

This base type is designed such that derived types can be processed in a generic manner; it assures that data structure definition specific data will have a consistent structure. The group, series, obs, and atts elements are unqualified, meaning that they are not qualified with a namespace in an instance. This means that in the derived data set types, the elements will always be the same, regardless of the target namespace of the schemas which defines these derived types. This allows for consistent processing of the structure without regard to what the namespace might be for the data structure definition specific schema.

+
+
+ + + + + + DataProvider contains a reference to the provider for the data set. + + + + + + Atts contains a set of data or metadata attribute values with an attachment level of none (i.e. data set level) or reported against a partial set of dimension values. + + + + + Group contains a references to a defined group in the data structure definition along with its key (if necessary) and values for the attributes which are associated with the group. An attribute is associated to a group by either an explicit group relationship or by a group attachment when the attribute has a relationship with a dimension which is a member of this group. + + + + + Series contains a collection of observations that share a common key (set of dimension values). The key of a series is every dimension defined in the data structure definition, save the dimension at the observation level. In addition to the key and observations, the series contains values for data and metadata attributes which have a relationship with any dimension that is part of the series key, so long as the attribute does not specify an attachment group or also has a relationship with the dimension declared to be at the observation level. + + + + + Obs is an un-grouped observation. This observation has a key which is a set of values for all dimensions declared in the data structure definition. In addition to the key, the value of the observation can be provided along with values for all data and metadata attributes which have an association with the observation or any dimension (so long as it does not specify a group attachment). + + + + + + Allows for attachment of reference metadata against to the data set. + + + + + + + +
+ + + + +

GroupType is the abstract type which defines a structure which is used to communicate attribute values for a group defined in a data structure definition. The group can consist of either a subset of the dimensions defined by the data structure definition, or an association to an attachment constraint, which in turn defines key sets to which attributes can be attached. In the case that the group is based on an attachment constraint, only the identification of group is provided. It is expected that a system which is processing this will relate that identifier to the key sets defined in the constraint and apply the values provided for the attributes appropriately.

+ +

Data structure definition schemas will drive types based on this for each group defined in the data structure definition. Both the dimension values which make up the key (if applicable) and the attribute values associated with the group will be represented with XML attributes. This is specified in the content model with the declaration of anyAttributes in the "local" namespace. The derived group type will refine this structure so that the attributes are explicit. The XML attributes will be given a name based on the attribute's identifier. These XML attributes will be unqualified (meaning they do not have a namespace associated with them). The dimension XML attributes will be required while the attribute XML attributes will be optional. To allow for generic processing, it is required that the only unqualified XML attributes in the derived group type be for the group dimensions and data or metadata attributes declared in the data structure definition. If additional attributes are required, these should be qualified with a namespace so that a generic application can easily distinguish them as not being meant to represent a data structure definition dimension or attribute.

+
+
+ + + + + + Comp contains the details of group level attributes that have complex representation and cannot be expressed as XML attributes. + + + + + Allows for attachment of reference metadata against to the group. + + + + + + The type attribute reference the identifier of the group as defined in the data structure definition. This is optional, but derived group types will provide a fixed value for this so that it always available in the post validation information set. This allows the group to be processed in a generic manner. + + + + + +
+ + + + +

SeriesType is the abstract type which defines a structure which is used to group a collection of observations which have a key in common. The key for a series is every dimension defined in the data structure definition, save the dimension declared to be at the observation level for this data set. In addition to observations, values can be provided for data and metadata attributes which are associated with the dimensions which make up this series key (so long as the attributes do not specify a group attachment or also have an relationship with the observation dimension). It is possible for the series to contain only observations or only attribute values, or both.

+ +

Data structure definition schemas will derive a type based on this that is specific to the data structure definition and the variation of the format being expressed in the schema. Both the dimension values which make up the key and the attribute values associated with the key dimensions will be represented with XML attributes. This is specified in the content model with the declaration of anyAttributes in the "local" namespace. The derived series type will refine this structure so that the attributes are explicit. The XML attributes will be given a name based on the attribute's identifier. These XML attributes will be unqualified (meaning they do not have a namespace associated with them). The dimension XML attributes will be required while the attribute XML attributes will be optional. To allow for generic processing, it is required that the only unqualified XML attributes in the derived group type be for the series dimensions and attributes declared in the data structure definition. If additional attributes are required, these should be qualified with a namespace so that a generic application can easily distinguish them as not being meant to represent a data structure definition dimension or attribute.

+
+
+ + + + + + Comp contains the details of series level attributes that have complex representation and cannot be expressed as XML attributes. + + + + + + Allows for attachment of reference metadata against to the series. + + + + + + The TIME_PERIOD attribute is an explict attribute for the time dimension. This is declared in the base schema since it has a fixed identifier and representation. The derived series type will either require or prohibit this attribute, depending on whether time is the observation dimension. If the time dimension specifies a more specific representation of time the derived type will restrict the type definition to the appropriate type. + + + + + +
+ + + + CompType is the abstract base for any component value (e.g. a data or metadata attribute, or a measure) that cannot be represented as an XML attribute. For example, a repeated value, a text value in multiple languages, or a value with structured text (XHTML) cannot be expressed as an XML attribute. This type is meant to be restricted based on the component to restrict the cardinality and type of its Value element to conform to the compoent definition. The type of the value element should be restricted to common:SimpleValueType, common:TextValueType, or common:StructuredValueType. In addition, the id attribute should be restricted to be a fixed value with the component identifier. This restricted type based on the component can then be used on Comp elements by using the xsi:type to state the component being expressed and refine the contents of the element to the values allowed by the component. + + + + + + + + + + + + + + + + + + +

ObsType is the abstract type which defines the structure of a grouped or un-grouped observation. The observation must be provided a key, which is either a value for the dimension which is declared to be at the observation level if the observation is grouped, or a full set of values for all dimensions in the data structure definition if the observation is un-grouped. This key should disambiguate the observation within the context in which it is defined (e.g. there should not be another observation with the same dimension value in a series). The observation can contain an observed value and/or attribute values.

+ +

Data structure definition schemas will derive a type or types based on this that is specific to the data structure definition and the variation of the format being expressed in the schema. The dimension value(s) which make up the key and the data and metadata attribute values associated with the key dimension(s) or the primary measure will be represented with XML attributes. This is specified in the content model with the declaration of anyAttributes in the "local" namespace. The derived observation type will refine this structure so that the attributes are explicit. The XML attributes will be given a name based on the attribute's identifier. These XML attributes will be unqualified (meaning they do not have a namespace associated with them). The dimension XML attribute(s) will be required while the attribute XML attributes will be optional. To allow for generic processing, it is required that the only unqualified XML attributes in the derived observation type be for the observation dimension(s) and attributes declared in the data structure definition. If additional attributes are required, these should be qualified with a namespace so that a generic application can easily distinguish them as not being meant to represent a data structure definition dimension or attribute.

+
+
+ + + + + + Comp contains the details of observation measures or attributes that have complex representation and cannot be expressed as XML attributes. + + + + + Allows for attachment of reference metadata against to the observation. + + + + + + The type attribute is used when the derived format requires that explicit measure be used. In this case, the derived type based on the measure will fix this value to be the identification of the measure concept. This will not be required, but since it is fixed it will be available in the post validation information set which will allow for generic processing of the data. If explicit measures are not used, then the derived type will prohibit the use of this attribute. + + + + + The TIME_PERIOD attribute is an explicit attribute for the time dimension. This is declared in the base schema since it has a fixed identifier and representation. The derived series type will either require or prohibit this attribute, depending on whether time is the observation dimension. If the time dimension specifies a more specific representation of time the derived type will restrict the type definition to the appropriate type. + + + + + +
+ + + + +

AttsType is the abstract type which defines a structure which is used to group a collection of data or metadata attributes which have a key in common. The key for a attribute collection is a subset of the dimension defined in the data structure definition. This is also used for data set level attributes (i.e. those with an attribute relationship of none). In this case, the subset of dimensions is empty.

+ +

Data structure definition schemas will derive a type based on this that is specific to the data structure definition. The dimension values which make up the key will be represented with local (non-namespace qualified) XML attributes. The metadata attribute values associated with the key dimensions will be expressed as XML local (non-namespace qualified) attributes if they are simple values (e.g. enumerated, dates, numbers) and are not repeatable. Metadata attributes that are repeatable, or do not have simple values (e.g. text) will be expressed using the Comp element. This dimensions and simple attributes are specified in the content model with the declaration of anyAttributes in the "local" namespace. The derived series type will refine this structure so that the attributes are explicit. The XML attributes will be given a name based on the attribute's identifier. These XML attributes will be unqualified (meaning they do not have a namespace associated with them). The dimension XML attributes will be required while the attribute XML attributes will be optional. To allow for generic processing, it is required that the only unqualified XML attributes in the derived group type be for the series dimensions and attributes declared in the data structure definition. If additional attributes are required, these should be qualified with a namespace so that a generic application can easily distinguish them as not being meant to represent a data structure definition dimension or attribute.

+
+
+ + + + + + Comp contains the details of the data or metadata attributes that have complex representation and cannot be expressed as XML attributes. + + + + + + The TIME_PERIOD attribute is an explict attribute for the time dimension. This is declared in the base schema since it has a fixed identifier and representation. The derived series type will either require or prohibit this attribute, depending on whether time is the observation dimension. If the time dimension specifies a more specific representation of time the derived type will restrict the type definition to the appropriate type. + + + + + +
+ + + + The SetAttributeGroup defines a common set of attributes pertaining to any data set. The attributes are qualified, so that they will be easily distinguished from attributes that are specific to the data structure. Note that many of these attributes are duplications of fields available in the header of the data messages. The reason for this is to allow the header values to be overridden at the data set level when a message contains more than one data set. If an attribute here does not have a value, then the value from the header is applied to the data set. + + + + The structureRef contains a reference to a structural specification in the header of a data or reference metadata message. The structural specification details which structure the data or reference metadata conforms to, as well as providing additional information such as how the data is structure (e.g. which dimension occurs at the observation level for a data set). + + + + + The setID provides an identification of the data or metadata set. + + + + + The action attribute indicates whether the file is appending, replacing, or deleting. + + + + + The reportingBeginDate indicates the inclusive start time of the data reported in the data or metadata set. + + + + + The reportingEndDate indicates the inclusive end time of the data reported in the data or metadata set. + + + + + The validFromDate indicates the inclusive start time indicating the validity of the information in the data or metadata set. + + + + + The validToDate indicates the inclusive end time indicating the validity of the information in the data or metadata set. + + + + + The publicationYear holds the ISO 8601 four-digit year. + + + + + The publicationPeriod specifies the period of publication of the data or metadata in terms of whatever provisioning agreements might be in force (i.e., "Q1 2005" if that is the time of publication for a data set published on a quarterly basis). + + + + +
\ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXMessage.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXMessage.xsd new file mode 100644 index 0000000..d6709f6 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXMessage.xsd @@ -0,0 +1,514 @@ + + + + + + + + + + + + + SDMX Message Namespace Module + The message namespace module contains the common message constructs, including the common header information which is used with all other SDMX-ML namespace modules. + + + + + + + MessageType is an abstract type which is used by all of the messages, to allow inheritance of common features. Every message consists of a mandatory header, followed by optional payload (which may occur multiple times), and finally an optional footer section for conveying error, warning, and informational messages. + + + + + + + + + + + + + Structure is a message that contains structural metadata. It may contain any of the following; categorisations, category schemes, code lists, concepts (concept schemes), constraints (attachment and content) data flows, hierarchical code lists, metadata flows, metadata structure definitions, organisation schemes, processes, reporting taxonomies, and structure sets. + + + + + + StructureType defines the contents of a structure message. The payload is optional since this message may be returned from a web service with only information in the footer. + + + + + + + + + + + + + + + + + StructureSpecificData is used to convey data structure specific according to data structure definition. The payload of this message (i.e. the data sets) will be based on XML schemas which are specific to the data structure definition and the orientation (i.e. the observation dimension) of the data. + + + + + + StructureSpecificDataType defines the structure of the structure specific data message. Note that the data set payload type is abstract, and therefore it will have to be assigned a type in an instance. This type must be derived from the base type referenced. This base type defines a general structure which can be followed to allow for generic processing of the data even if the exact details of the data structure specific format are not known. + + + + + + + + + + + + + + + + + GenericMetadata contains reported metadata in a format which supports any metadata structure definition. + + + + + + GenericMetadataType defines the contents of a generic metadata message. + + + + + + + + + + + + + + + + + RegistryInterface is used to conduct all interactions with the SDMX Registry Services. + + + + + + This is a type which describes a structure for holding all of the various dedicated registry interface message types. + + + + + + + + + SubmitRegistrationsRequest is sent to the registry by an agency or data/metadata provider to request one or more registrations for a data set or metadata set. The data source to be registered must be accessible to the registry services at an indicated URL, so that it can be processed by those services. + + + + + SubmitRegistrationsResponse is sent to the agency or data/metadata provider in response to a submit registrations request. It indicates the success or failure of each registration request, and contains any error messages generated by the registration service. + + + + + QueryRegistrationRequest is used to query the contents of a registry for data sets and metadata sets. It specifies whether the result set should include metadata sets, data sets, or both. The search can be characterized by providing constraints including reference periods, data regions, and data keys. + + + + + QueryRegistrationResponse is sent as a response to any query of the contents of a registry. The result set contains a set of links to data and/or metadata If the result set is null, or there is some other problem with the query, then appropriate error messages and statuses will be returned. + + + + + SubmitStructureRequest is used to submit structure definitions to the repository. The structure resources (key families, agencies, concepts and concept schemes, code lists, etc.) to be submitted may be communicated in-line or be supplied in a referenced SDMX-ML Structure messages external to the registry. A response will indicate status and contain any relevant error information. + + + + + SubmitStructureResponse is returned by the registry when a structure submission request is received. It indicates the status of the submission, and carries any error messages which are generated, if relevant. + + + + + SubmitSubscriptionsRequest contains one or more requests submitted to the registry to subscribe to registration and change events for specific registry resources. + + + + + SubmitSubscriptionsResponse is the response to a submit subscriptions request. It contains information which describes the success or failure of each subscription request, providing any error messages in the event of failure. If successful, it returns the registry URN of the subscription, and the subscriber-assigned ID. + + + + + QuerySubscriptionRequest is used to query the registry for the subscriptions of a given organisation. + + + + + QuerySubscriptionResponse is sent as a response to a subscription query. If the query is successful, the details of all subscriptions for the requested organisation are sent. + + + + + NotifyRegistryEvent is sent by the registry services to subscribers, to notify them of specific registration and change events. Basic information about the event, such as the object that triggered it, the time of the event, the action that took place, and the subscription that triggered the notification are always sent. Optionally, the details of the changed object may also be provided. + + + + + + + + + + + + SubmitStructureRequest is used to submit structure definitions to the repository. The structure resources (key families, agencies, concepts and concept schemes, code lists, etc.) to be submitted may be communicated in-line or be supplied in a referenced SDMX-ML Structure messages external to the registry. A response will indicate status and contain any relevant error information. + + + + + + SubmitStructureRequestType defines the structure of a registry submit structure request document. + + + + + + + + + + + + + + SubmitStructureResponse is returned by the registry when a structure submission request is received. It indicates the status of the submission, and carries any error messages which are generated, if relevant. + + + + + + SubmitStructureResponseType defines the structure of a registry submit registration response document. + + + + + + + + + + + + + + + + + Error is used to communicate that an error has occurred when responding to a request in an non-registry environment. The content will be a collection of error messages. + + + + + + ErrorType describes the structure of an error response. + + + + + ErrorMessage contains the error message. It can occur multiple times to communicate message for multiple errors, or to communicate the error message in parallel languages. If both messages for multiple errors and parallel language messages are used, then each error message should be given a code in order to distinguish message for unique errors. + + + + + + + + + + BaseHeaderType in an abstract base type that defines the basis for all message headers. Specific message formats will refine this + + + + + ID identifies an identification for the message, assigned by the sender. + + + + + Test indicates whether the message is for test purposes or not. + + + + + Prepared is the date the message was prepared. + + + + + Sender is information about the party that is transmitting the message. + + + + + Receiver is information about the party that is the intended recipient of the message. + + + + + Name provides a name for the transmission. Multiple instances allow for parallel language values. + + + + + Structure provides a reference to the structure (either explicitly or through a structure usage reference) that describes the format of data or reference metadata. In addition to the structure, it is required to also supply the namespace of the structure specific schema that defines the format of the data/metadata. For cross sectional data, additional information is also required to state which dimension is being used at the observation level. This information will allow the structure specific schema to be generated. For generic format messages, this is used to simply reference the underlying structure. It is not mandatory in these cases and the generic data/metadata sets will require this reference explicitly. + + + + + DataProvider identifies the provider of the data for a data message. + + + + + MetadataProvider identifies the provider of the metadata for a metadata message. + + + + + DataSetAction code provides a code for determining whether the enclosed message is an Update or Delete message (not to be used with the UtilityData message). + + + + + DataSetID provides an identifier for a contained data set. + + + + + Extracted is a time-stamp from the system rendering the data. + + + + + ReportingBegin provides the start of the time period covered by the message (in the case of data). + + + + + ReportingEnd provides the end of the time period covered by the message (in the case of data). + + + + + EmbargoDate holds a time period before which the data included in this message is not available. + + + + + Source provides human-readable information about the source of the data. + + + + + + + + StructureHeaderType defines the structure for structural metadata messages. + + + + + + + + + + + + + + + + + + + StructureSpecificDataHeaderType defines the header structure for a structure specific data message. + + + + + + + + + + + + + + + + + + + + + + + + + + + GenericMetadataHeaderType defines the header format for generic reference metadata. + + + + + + + + + + + + + + + + + + + + + + + + BasicHeaderType defines the most basic header information used in simple message exchanges. + + + + + + + + + + + + + + + + + PartyType defines the information which is sent about various parties such as senders and receivers of messages. + + + + + Name is a human-readable name of the party. + + + + + Contact provides contact information for the party in regard to the transmission of the message. + + + + + + The id attribute holds the identification of the party. + + + + + + + SenderType extends the basic party structure to add an optional time zone declaration. + + + + + + + Timezone specifies the time zone of the sender, and if specified can be applied to all un-time zoned time values in the message. In the absence of this, any dates without time zone are implied to be in an indeterminate "local time". + + + + + + + + + + ContactType provides defines the contact information about a party. + + + + + Name contains a human-readable name for the contact. + + + + + Department is designation of the organisational structure by a linguistic expression, within which the contact person works. + + + + + Role is the responsibility of the contact person with respect to the object for which this person is the contact. + + + + + + Telephone holds the telephone number for the contact person. + + + + + Fax holds the fax number for the contact person. + + + + + X400 holds the X.400 address for the contact person. + + + + + URI holds an information URL for the contact person. + + + + + Email holds the email address for the contact person. + + + + + + + + + Provides a union type of xs:date and xs:dateTime for the header fields in the message. + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXMessageFooter.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXMessageFooter.xsd new file mode 100644 index 0000000..fe0b539 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXMessageFooter.xsd @@ -0,0 +1,57 @@ + + + + + + + + + Footer is used to communicate information such as error and warnings after the payload of a message. + + + + + + FooterType describes the structure of a message footer. The footer is used to convey any error, information, or warning messages. This is to be used when the message has payload, but also needs to communicate additional information. If an error occurs and no payload is generated, an Error message should be returned. + + + + + Message contains a single error, information, or warning message. A code is provided along with an optional severity. The text of the message can be expressed in multiple languages. + + + + + + + + FooterMessageType defines the structure of a message that is contained in the footer of a message. It is a status message that have a severity code of Error, Information, or Warning added to it. + + + + + + + + + + + + + Error indicates the status message coresponds to an error. + + + + + Warning indicates that the status message corresponds to a warning. + + + + + Information indicates that the status message corresponds to an informational message. + + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXMetadataGeneric.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXMetadataGeneric.xsd new file mode 100644 index 0000000..1fd00ea --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXMetadataGeneric.xsd @@ -0,0 +1,112 @@ + + + + + + + SDMX Generic Metadata Namespace Module + The generic metadata namespace module describes a generic format for the reporting of reference metadata, regardless of the underlying metadata structure definition. + + + + + MetadataSetBaseType defines the base refinement of the MetadataSetType. Its purpose is to restrict the urn attribute. + + + + + + + + + + + + + + + + + MetadataSetType describes the structure for a metadata set, which contains a collection of reported metadata against a set of targets. The targets should conform to the restrictions described by the metadata provision or the metadataflow. Note that this is maintainble, and as such must specify in agency. In this case, the agency is the metadata provider. If a metadata provision agreement is referenced, it is assumed that the metadata provider described in the provision will be the same as the agency for this set. + + + + + + + + Metadataflow provides a reference to the. + + + + + Metadataflow provides a reference to the metadataflow the metadata set is being reported against. + + + + + + Target references the target structures for which metadata is being reported. These must conform with the constraints defined by the metadata provision agreement and/or the metadataflow. + + + + + Att elements hold the reported metadata attribute values being reported in the metadata set. These conform to the metadata structure defintion + + + + + + + + + + + Att elements hold the reported values for a given metadata attribute. These values conform to the definition of the meatadata attribute in the metadata structure definition. + + + + + + + + + + AttributeType defines the structure for a reported metadata attribute. A value for the attribute can be supplied as either a single value (enumerated or non-enumerated single value), or multi-lingual text values (either structured or unstructured). Optional child attributes ar also available if the metadata attribute definition defines nested metadata attributes. + + + + + + + + Value holds any simple value (enumerated or not) for the metadata attribute. It can be repeated if this metadata attribute allows for multiple values. + + + + + Text is used to supply parallel multi-lingual textual values for the reported metadata attribute. This will be used if the text format of the metadata attribute has a type of string and the multi-lingual value is set to true. + + + + + StructuredText is used to supply parallel multi-lingual structured (as XHTML) textual values for the reported metadata attribute. This will be used if the text format of the metadata attribute has a type of XHTML and the multi-lingual value is set to true. + + + + + + Att contains the reported metadata attribute values for the child metadata attributes. + + + + + + The id attribute identifies the metadata attribute that the value is being reported for. + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistry.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistry.xsd new file mode 100644 index 0000000..c890753 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistry.xsd @@ -0,0 +1,14 @@ + + + + + + + + + + SDMX Registry Namespace Module + The registry namespace module describes the standard interfaces for interactions with a set of registry services. For convenience, this module has been broken down into sub-modules for the different registry functions. + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistryBase.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistryBase.xsd new file mode 100644 index 0000000..c5a687a --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistryBase.xsd @@ -0,0 +1,224 @@ + + + + + + + SDMX Base Registry Module + The base registry module defines the common constructs that a reused across multiple registry functions. + + + + + Registration provides the information needed for data and reference metadata set registration. A data source must be supplied here if not already provided in the provision agreement. The data set or metadata set must be associated with a provision agreement, a metadata flow, or a dataflow definition. If possible, the provision agreement should be specified. Only in cases where this is not possible should the dataflow or metadata flow be used. + + + + + ProvisionAgreement provides a reference to the provision agreement that the data is being registered against. + + + + + Datasource identifies the data source(s) where the registered data can be retrieved. + + + + + + + + + + The id attribute holds a registry assigned identification for the registration. This must be provided in a response message (unless an error occurred while submitting a new registration), and should be included when updating or deleting a registration. + + + + + The validFrom attribute provides an inclusive start date for providing supplemental validity information about the registration, so that data visibility from the registry can be controlled by the registrant. + + + + + The validFrom attribute provides an inclusive end date for providing supplemental validity information about the registration, so that data visibility from the registry can be controlled by the registrant. + + + + + The lastUpdated attribute provides a timestamp for the last time the data source was updated. + + + + + The indexTimeSeries, if true, indicates that the registry must index all time series for the registered data. The default value is false, and the attribute will always be assumed false when the provision agreement references a metadata flow. + + + + + The indexDataSet, if true, indicates that the registry must index the range of actual (present) values for each dimension of the data set or identifier component of the metadata set (as indicated in the set's structure definition). The default value is false. + + + + + The indexAttributes, if true, indicates that the registry must index the range of actual (present) values for each attribute of the data set or the presence of the metadata attributes of the metadata set (as indicated in the set's structure definition). The default value is false. + + + + + The indexReportingPeriod, if true, indicates that the registry must index the time period ranges for which data is present for the data source. The default value is false, and the attribute will always be assumed false when the provision agreement references a metadata flow. + + + + + + + DataSourceType specifies the properties of a data or metadata source. Either a simple data source, a queryable data source, or both must be specified. + + + + + SimpleDatasource describes a data source that is an SDMX-ML data or metadata message. It requires only the URL of the data. + + + + + QueryableDatasource describes a data source that can be queried using the SDMX REST interfaces. + + + + + + + + SimpleDataSourceType describes a simple data source. The URL of the data is contained in the content. + + + + + + TYPE is a fixed attribute that is used to ensure only one simple data source may be provided, when it is referenced in a uniqueness constraint. + + + + + + + + + QueryableDataSourceType describes a queryable data source, and add a fixed attribute for ensuring only one queryable source can be provided. + + + + + + TYPE is a fixed attribute that is used to ensure only one queryable data source may be provided, when it is referenced in a uniqueness constraint. + + + + + + + + + IDQueryType is a simple type that allows for an identifier to be substituted with a wild card character ("%"). + + + + + + + NestedIDQueryType is a simple type that allows for a nested identifier to be substituted with a wild card character ("%"). + + + + + + + VersionQueryType is a simple type that allows for a version number to be substituted with a wild card character ("%") or a late bound character ("*"). + + + + + + + IdentifiableQueryType describes the structure of a query for an identifiable object. + + + + The id attribute is used to query for an object based on its identifier. This is either an explicit value, or completely wild cared with the "%" value. + + + + + + + VersionableQueryType describes the structure of a query for a versionable object. + + + + + + The version attribute is used to query for an object based on its version. This can be and explicit value, wild-carded ("%"), or late-bound ("*"). A wild carded version will match any version of the object where as a late-bound version will only match the latest version. + + + + + + + + + MaintainableQueryType describes the structure of a query for a maintainable object. + + + + + + The agencyID attribute is used to query for an object based on its maintenance agency's identifier. This is either an explicit value, or completely wild cared with the "%" value. + + + + + + + + + StatusMessageType carries the text of error messages and/or warnings in response to queries or requests. + + + + + MessageText contains the text of the error and/or warning message. It can occur multiple times to communicate message for multiple warnings or errors. + + + + + + The status attribute carries the status of the query or request. + + + + + + + StatusType provides an enumeration of values that detail the status of queries or requests. + + + + + Query or request successful. + + + + + Query or request successful, but with warnings. + + + + + Query or request not successful. + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistryRegistration.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistryRegistration.xsd new file mode 100644 index 0000000..ba361f6 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistryRegistration.xsd @@ -0,0 +1,218 @@ + + + + + + + + + SDMX Registration Registry Module + The registration registry module defines the constructs that are used for the maintenance and discovery of data and reference metadata in a registry. + + + + + SubmitRegistrationsRequestType defines the payload of a request message used to submit addtions, updates, or deletions of data/metadata set registrations. + + + + + RegistrationRequest provides the details of a requested registration and the action to take on it. A reference to a provision agreement that exists in the registry must be provide along with a simple and/or queryable data source. The id should only be provided when updating or deleting a registration. + + + + + + + + RegistrationRequestType describes the structure of a single registration request. It contains the details of a registation and an action field to indicate the action to be taken on the contained registration. + + + + + Registration contains the details of the data/metadata set registration to be added, updated, or deleted. + + + + + + The action attribute indicates whether this is an addition, a modification, or a deletion of a registration. + + + + + + + SubmitRegistrationsResponseType describes the structure of a registration response. For each submitted registration in the request, a registration status is provided. The status elements should be provided in the same order as the submitted registrations, although each status will echo the request to ensure accurate processing of the responses. + + + + + RegistrationStatus provided the status details for the submitted registration. It echoes the original submission and provides status information about the request. + + + + + + + + RegistrationStatusType describes the structure of a registration status. + + + + + Registration, at the very least echoes the submitted registration. It the request was to create a new registration and it was successful, an id must be supplied. + + + + + StatusMessage provides that status for the registration request, and if necessary, any error or warning information. + + + + + + + + QueryRegistrationRequestType describes the structure of a registration query request. The type of query (data, reference metadata, or both) must be specified. It is possible to query for registrations for a particular provision agreement, data provider, or structure usage, or to query for all registrations in the registry. In addition the search can be refined by providing constraints in the form of explicit time periods, constraint regions, and key sets. When constraint regions and key sets are provided they will be effectively processed by first matching all data for the included keys and regions (all available data if there are none) and then removing any data matching the excluded keys or regions. + + + + + QueryType defines the type of sets (data, metadata, or both) that are being queried for. + + + + + + All indicates that all registrations meeting the other criteria of the query should be returned. + + + + + ProvisionAgreement provides a reference to a provision agreement in the registry, for which all registered sets meeting the other criteria of this query should be returned. The reference is provided as a URN and/or a complete set of reference fields. + + + + + DataProvider provides a reference to a data provider in the registry, for which all registered sets meeting the other criteria of this query should be returned. The reference is provided as a URN and/or a complete set of reference fields. + + + + + Dataflow provides a reference to a data flow in the registry, for which all registered sets meeting the other criteria of this query should be returned. The reference is provided as a URN and/or a complete set of reference fields. + + + + + Metadataflow provides a reference to a metadata flow in the registry, for which all registered sets meeting the other criteria of this query should be returned. The reference is provided as a URN and/or a complete set of reference fields + + + + + + ReferencePeriod provides an inclusive start and end date for the data or metadata being sought. + + + + + + DataKeySet is used to provide a set of included or excluded keys which serves to refine the data being sought. + + + + + CubeRegion is used to provide sets of include or excluded values for dimensions when querying for data. + + + + + MetadataTargetRegion is used to provide sets of included or excluded values for identifier components when querying for metadata. + + + + + + + The returnConstraints attribute determines whether information about the constraints on the data or metadata sets returned should also be sent the results. + + + + + + + QueryRegistrationResponseType describes the structure of a registration query response. It provides a status for the request, and if successful, the resulting data and/or metadata results. + + + + + StatusMessage provides that status for the registration query request, and if necessary, any error or warning information. + + + + + QueryResult contains a result for a successful registration query. It can occur multiple times, for each registration the meets the conditions specified in the query. + + + + + + + + QueryResultType describes the structure of a query result for a single data source. Either a data result or metadata result is detailed, depending on the data source. + + + + + + + + + + The timeSeriesMatch attribute is true when the result is an exact match with the key found in the registry - that is, when the registered data source provides a matching key. It is set to false when the data source is registered with cube-region constraints, or in any other circumstance when it cannot be established that the sought-for keys have been exactly matched. This is always true when the resulting data source is the source of a metadata set. + + + + + + + ResultType contains the details about a data or metadata source, through the complete registration information. In addition, a reference to the content constraints for the data source may be provided, if the query requested this information. + + + + + Registration provides the details of a matching registration. In addition to the data source and provision agreement information, the id of the registration must also be provided. + + + + + Constraint provides a reference to a data or metadata constraint in the registry for the resulting data source (or possibly constraints base on the registration provision agreement, data provider, structure usage, or structure). The reference is provided for by a URN and/or a complete set of reference fields. + + + + + + + + QueryType provides an enumeration of values which specify the objects in the result-set for a registry query. + + + + + Only references data sets should be returned. + + + + + Only references to metadata sets should be returned. + + + + + References to both data sets and metadata sets should be returned. + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistryStructure.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistryStructure.xsd new file mode 100644 index 0000000..cd6cd92 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistryStructure.xsd @@ -0,0 +1,98 @@ + + + + + + + + + SDMX Structure Registry Module + The structure registry module defines the constructs that are used for the maintenance and discovery of structural metadata in a registry. + + + + + SubmitStructureRequestType describes the structure of a structure submission. Structural components are provided either in-line or referenced via a SDMX-ML Structure message external to the registry. A default action and external reference resolution action are all provided for each of the contained components, but can be overridden on a per component basis. + + + + + + StructureLocation provides the location of a SDMX-ML Structure message, external to the repository that can be retrieved by the repository submission service. + + + + + Structures allows for the inline definition of structural components for submission. + + + + + + SubmittedStructure contains a reference to one of the structural maintainable artefacts detailed in the external SDMX-ML Structure message or in-line and provides an override for the default action. This should only be used if the action to be performed on the referenced structural object is different than the default action. For example, one may want to append all structural components of a structure message, save one codelist. This codelist could be referenced in a submitted structure element and given an action of Informational. + + + + + + The action attribute indicates the default action (append-add, replace-update, delete, or no action-informational) to be taken on all structural components in either the external SDMX-ML Structure message or the in-line components. The default action is Append. The Replace action is not applicable to final structures in the repository, and will produce an error condition, as these can be versioned but not modified. To submit a later version of a structural object, the object should include the incremented version number. + + + + + The externalDependencies attribute indicates the default resolution of external dependencies. This should be set to true if the repository is expected to use external reference URLs in the structural components to retrieve any externally referenced objects that is used by a non-external object. + + + + + + + SubmittedStructureType generally references a submitted structural object. When used in a submit structure request, its purpose is to override the default action or external dependency resolution behavior. If neither of these indicators are set, then it will be ignored. In a submit structure response, it is used to reference a submitted object for the purpose of providing a status for the submission. In this case, the action attribute should be populated in order to echo the requested action. + + + + + + + The action attribute will indicate the action to be taken on the referenced structural object. This should be provided when this structure is used in a submit structure response. + + + + + The externalDependencies attribute should be set to true if the repository is expected to use external reference URLs in the structural components to retrieve objects on which the referenced object has dependencies. (Thus, if a data structure referenced here is being submitted to the repository, and the structure message has URLs which point to the locations of the codelists it uses, then this attribute should be set to true). This should not be provided when this structure is used in a submit structure response. + + + + + + + SubmitStructureResponseType describes the structure of a response to a structure submission. For each submitted structure, a Result will be returned. + + + + + SubmissionResult provides a status for each submitted structural object. + + + + + + + + SubmissionResultType provides the status of the structural object submission request. It will identify the object submitted, report back the action requested, and convey the status and any error messages which are relevant to the submission. + + + + + SubmittedStructure provides a reference to the submitted structural object and echoes back the action requested for it. + + + + + StatusMessage provides that status for the submission of the structural object, and if necessary, any error or warning information. + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistrySubscription.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistrySubscription.xsd new file mode 100644 index 0000000..873e261 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXRegistrySubscription.xsd @@ -0,0 +1,603 @@ + + + + + + + + + SDMX Subscription Registry Module + The subscription registry module defines the constructs that are used for the maintenance and usage of notification subscriptions in a registry. + + + + + SubmitSubscriptionsRequestType defines the payload of a request message used to submit addtions, updates, or deletions of subscriptions. Subscriptions are submitted to the registry to subscribe to registration and change events for specific registry resources. + + + + + + + + + SubscriptionType describes the details of a subscription to a registration or change event for registry resources. When it occurs as the content of a response message, the registry URN must be provide, unless the response is a failure notification for the creation of a new subscription. + + + + + Organisation provides a reference to the organisation that owns this subscription. The reference is provided via a URN and/or a complete set of reference fields. + + + + + RegistryURN is used to identify the subscription in the case of deletion or modification. This should be provided in all response messages, unless the response it a notification of the failure to create a newly submitted subscription - in which case there will be no registry assigned URN. + + + + + NotificationMailTo holds an e-mail address (the "mailto:" protocol). Multiple email address can be notified for a single subscription. + + + + + NotificationHTTP holds an http address to which notifications can be addressed as POSTs. Multiple http address may be notified for a single subscription event. + + + + + SubscriberAssignedID allows the subscriber to specify an identification which will be returned as part of the notification for the subscribed events. This should be used if multiple new requests are made, so that the responses can be accurately correlated to the requests. + + + + + Validity period sets a start and end date for the subscription. + + + + + EventSelector indicates an event or events for the subscription. + + + + + + + + + + + + SubscriptionRequestType describes the structure of a single subscription request. It contains subscription details and an action field to indicate the action to be taken on the contained subscription. Note that if the action is update or delete, then the registry supplied URN for the subscription must be included. + + + + + Subscription contains the details of the subscription to be added, updated, or deleted. + + + + + + The action attribute indicates whether this is an addition, a modification, or a deletion of a subscription. + + + + + + + SubmitSubscriptionsResponseType describes the structure of the response to a new subscription submission. A status is provided for each subscription in the request. + + + + + SubscriptionStatus contains information which describes the success or failure of a subscription request, providing any error messages in the event of failure. The statuses should occur in the same order as the requests when responding to a message with multiple subscription requests. If a subscriber-assigned identification for the subscription is provided, it will be returned to allow for accurate matching of the responses to the requests. A registry assigned URN will be returned for any successfully created, updated, or deleted subscription. + + + + + + + + SubscriptionStatusType describes the structure a status for a single subscription request. + + + + + SubscriptionURN contains the registry generated URN for the subscription, and will be returned for any successfully created, updated, or deleted subscription. + + + + + SubscriberAssignedID is the id assigned by the subscriber to the subscription. If it existed in the subscription request, it will be returned. + + + + + StatusMessage provides that status for the subscription request, and if necessary, any error or warning information. + + + + + + + + QuerySubscriptionRequestType describes the structure of a query for subscriptions. Subscriptions for a given organisation may be retrieved. + + + + + Organisation provides a reference to the data consumer for which the subscription details should be returned. + + + + + + + + QuerySubscriptionResponseType describes the structure of a subscription query response. A status will describe the success or failure of the request (and provide error or warning messages if necessary). If the query was successful, details of all of the organisation's subscriptions will be provided. + + + + + StatusMessage provides that status for the query subscription request, and if necessary, any error or warning information. + + + + + Subscription contains the details of a subscription for the organisation. This may occur multiple times for each subscription. + + + + + + + + NotifyRegistryEventType describes the structure a registry notification, in response to a subscription to a registry event. At a minimum, the event time, a reference to the change object, a reference to the underlying subscription triggering the notification, and the action that took place on the object are sent. In addition, the full details of the object may be provided at the discretion of the registry. In the event that the details are not sent, it will be possible to query for the details of the changed object using the reference provided. + + + + + EventTime specifies the time of the triggering event. + + + + + + ObjectURN provides the URN of the object on which the event occurred, unless the event is related to a registration, in which case the RegistrationID element should be used. + + + + + RegistrationID provides the id of the registration that underwent an event. + + + + + + SubscriptionURN provides the registry/repository URN of the subscription that is the cause of this notification being sent. + + + + + EventAction indicates the nature of the event - whether the action was an addition, a modification, or a deletion. + + + + + + StructuralEvent is used to provide the details of the structural object that has changed. + + + + + RegistrationEvent is used to provide the details or the registration object that has changed. + + + + + + + + + NotificationURLType describes the structure of an http or email address. The content holds the addresses while an attribute indicates whether or not is expects the contents in a SOAP message. + + + + + + The isSOAP attribute, if true, indicates the provided URL expects the notification to be sent in a SOAP message. + + + + + + + + + ValidityPeriodType specifies inclusive start and end-dates for the subscription period. + + + + + StartDate is an inclusive start date for the subscription. + + + + + EndDate is an inclusive end date for the subscription. + + + + + + + + EventSelectorType describes the details of the events for a subscription. It allows subscribers to specify registry and repository events for which they wish to receive notifications. + + + + + StructuralRepositoryEvents details structural events for the subscription. + + + + + DataRegistrationEvents details the data registration events for the subscription. + + + + + MetadataRegistrationEvents details the metadata registration events for the subscription. + + + + + + + + StructuralRepositoryEventsType details the structural events for the subscription. At least one maintenance agency must be specified, although it may be given a wildcard value (meaning the subscription is for the structural events of all agencies). This can also be a list of agencies to allow the subscription to subscribe the events of more than one agency. It should be noted that when doing so, all of the subsequent objects are assumed to apply to every agency in the list. The subscription is then refined by detailing the structural objects maintained by the agency for which the subscription should apply. It is possible to explicitly select all object events, all objects of given types, or to individually list out specific objects. Note that for any object, it is also possible to provide an explicit URN to reference a distinct object. In this case, the reference to maintenance agency described above is ignored. Although it is not required, if specific objects are being referenced by explicit URNs, it is good practice to list the agencies. + + + + + AgencyID specifies a maintenance agency for the object or objects indicated in the other fields. This can be either a specific ID, or a single wildcard character ("%"). A wild card character can be used to select all agencies, allowing a subscription to all events for particular object types. This can occur multiple times to list a of group of maintenance agencies, creating event subscriptions for all of the subsequent objects for each agency in the group. Note that if multiple agencies are supplied, then the wildcard character should not be used for any of them. + + + + + + AllEvents creates a subscription to structural events for all structural objects maintained by the agencies referenced. + + + + + + AgencyScheme is used to subscribe to changes of agency schemes. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + DataConsmerScheme is used to subscribe to changes of data consumer schemes. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + DataProviderScheme is used to subscribe to changes of data provider schemes. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + OrganisationUnitScheme is used to subscribe to changes of organisation unit schemes. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + Dataflow is used to subscribe to changes of data flows. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + Metadataflow is used to subscribe to changes of metadata flows. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + CategoryScheme is used to subscribe to changes of category schemes. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + Categorisation is used to subscribe to changes of categorizations. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id field can be selected. + + + + + Codelist is used to subscribe to changes of code lists. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + HierarchicalCodelist is used to subscribe to changes of hierarchical code lists. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + ConceptScheme is used to subscribe to changes of concept schemes. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + MetadataStructureDefinition is used to subscribe to changes of metadata structure definitions. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + KeyFamily is used to subscribe to changes of key families. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + StructureSet is used to subscribe to changes of structure sets. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + ReportingTaxonomy is used to subscribe to changes of reporting taxonomies. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + Process is used to subscribe to changes of processes. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + AttachmentConstraint is used to subscribe to changes of attachment constraints. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + ContentConstraint is used to subscribe to changes of content constraints. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + ProvisionAgreement is used to subscribe to changes of a provision agreement. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + TransformationScheme is used to subscribe to changes of a transformation scheme. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + NameAliasScheme is used to subscribe to changes of a name alias scheme. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + NamePersonalisationScheme is used to subscribe to changes of a name peronsalisation scheme. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + RulesetScheme is used to subscribe to changes of a ruleset scheme. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + UserDefinedOperatorScheme is used to subscribe to changes of a user defined operator scheme. The maintenance agencies of the object are those identified in the AgencyID collection, effectively making separate version of this query for each agency specified. The agency is ignored if the content of this is a URN, which references an explicit object. Otherwise, either all objects of this type or specific object according to the id and version fields can be selected. + + + + + + + + TYPE is a fixed attribute that is used to ensure only of each event selector may be provided, when it is referenced in a uniqueness constraint. + + + + + + + IdentifiableObjectEventType describes the structure of a reference to an identifiable object's events. Either all instances of the object matching the inherited criteria, a specific instance, or specific instances of the object may be selected. + + + + + All subscribes to the events all instances of the containing object meeting the other criteria specified. + + + + + URN subscribes to the events of the specific instance of the object type referenced by this URN. Note that when this field is used, the agency information inherited from the structural repository event container is ignored. + + + + + + ID subscribes to the events of the specific instance of the object type where the value provided here matches the id of the object. The default value is the wildcard character("%"). + + + + + + + + + VersionableObjectEventType describes the structure of a reference to a versionable object's events. Either all instances of the object matching the inherited criteria, a specific instance, or specific instances of the object may be selected. + + + + + All subscribes to the events all instances of the containing object meeting the other criteria specified. + + + + + URN subscribes to the events of the specific instance of the object type referenced by this URN. Note that when this field is used, the agency information inherited from the structural repository event container is ignored. + + + + + + ID subscribes to the events of the specific instance of the object type where the value provided here matches the id of the object and the value provided in the version field matches the version of the object. The default value is the wildcard character("%"). + + + + + Version subscribes to the events of the specific instance of the object type where the value provided in the id field matches the id of the object and the value here matches the version of the object. The default value is the wildcard character("%"). Note that in addition to being wild-carded, this can also be bound to the latest version of the object with the late-bound character("*"). + + + + + + + + + DataRegistrationEventsType details the data registration events for the subscription. It is possible to subscribe to all data registration events in the repository, or specific events for; single registrations, provision agreements, data providers, data flows, key families, and categories that categorize data flows or key families. + + + + + AllEvents subscribes to all data registration events in the repository. + + + + + + RegistrationID subscribes to all the data registration events for the unique registration referenced. + + + + + ProvisionAgreementReference subscribes to all data registration events for the explicitly referenced provision agreement. + + + + + DataProviderReference subscribes to all data registration events for the explicitly referenced data provider. + + + + + DataflowReference subscribes to all data registration events for the data flows referenced by this object. This may reference one or more data flows, as the specific references fields allow for a wild-carded value. + + + + + KeyFamilyReference subscribes to all data registration events for the key families referenced by this object. This may reference one or more key families, as the specific references fields allow for a wild-carded value. + + + + + Category subscribes to all data registration events for any data flows or key families that are categorized by the referenced category. + + + + + + + TYPE is a fixed attribute that is used to ensure only of each event selector may be provided, when it is referenced in a uniqueness constraint. + + + + + + + MetadataRegistrationEventsType details the metadata registration events for the subscription. It is possible to subscribe to all metadata registration events in the repository, or specific events for; single registrations, provision agreements, data providers, metadata flows, metadata structure definitions, and categories that categorize metadata flows or metadata structure definitions. + + + + + AllEvents subscribes to all metadata registration events in the repository. + + + + + + RegistrationID subscribes to all the metadata registration events for the unique registration referenced. + + + + + ProvisionAgreementReference subscribes to all metadata registration events for the explicitly referenced provision agreement. + + + + + DataProvider subscribes to all metadata registration events for the explicitly referenced data provider. + + + + + MetadataflowReference subscribes to all metadata registration events for the metadata flows referenced by this object. This may reference one or more metadata flows, as the specific references fields allow for a wild-carded value. + + + + + MetadataStructureDefinitionReference subscribes to all metadata registration events for the metadata structure definitions referenced by this object. This may reference one or more metadata structure definitions, as the specific references fields allow for a wild-carded value. + + + + + Category subscribes to all metadata registration events for any metadata flows or metadata structure definitions that are categorized by the referenced category. + + + + + + + TYPE is a fixed attribute that is used to ensure only of each event selector may be provided, when it is referenced in a uniqueness constraint. + + + + + + + MaintainableEventType provides a reference to a maintainable object's event with either the URN of the specific object, or a set of potentially wild-carded reference fields. + + + + + URN provides an explicit reference to a single object. + + + + + Ref provides a reference to potentially many object through the use of possible wild-carded reference fields. + + + + + + + + StructuralEventType provides the details of a structure event, specifically the object that changed. + + + + + Structures contains the details of the structural object that has triggered the event. Although this container allows for multiple structural object, it should only contain the one changed object. + + + + + + + + This provides the details of a data or metadata registration event for the purposes of notification. + + + + + Registration provides the changed details of the data or metadata registration. + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructure.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructure.xsd new file mode 100644 index 0000000..68fa7ba --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructure.xsd @@ -0,0 +1,1009 @@ + + + + + + + + + + + + + + + + + + + + + + + SDMX Structure Namespace Module + The structure namespace module contains the descriptions of structural metadata such as key families, concepts, and codelists. For convenience, this module has been broken down into sub-modules for the different type of structural constructs. + + + + + Structures contains constructs for all structural metadata components. + + + + + + StructuresType describes the structure of the container for all structural metadata components. The structural components may be explicitly detailed, or referenced from an external structure document or registry service. Best practices dictate that, at a minimum, any structural component that is referenced by another structural component be included by reference. + + + + + AgencySchemes contains a collection of agency scheme descriptions. The agency schemes may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + Categorisations contains a collection of structural object categorisations. This container may contain categorisations for many types of objects. The categorisations may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + CategorySchemeMaps contains a collection of category scheme map descriptions. The category scheme maps may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + CategorySchemes contains a collection of category scheme descriptions. The category schemes may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + Codelists contains a collection of code list descriptions. The code lists may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + ConceptSchemeMaps contains a collection of concept scheme map descriptions. The concept scheme maps may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + ConceptSchemes contains a collection of concept scheme descriptions. The concept schemes described are contained within schemes. The concepts may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + CustomTypeSchemes contains a collection of custom type schemes. The scheme may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + DataConstraints contains a collection of data constraint descriptions. The constraints may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + DataConsumerSchemes contains a collection of data consumer scheme descriptions. The data consumer schemes may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + Dataflows contains a collection of data flow descriptions. The data flows may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + DataProviderSchemes contains a collection of data provider scheme descriptions. The data provider schemes may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + DataStructures contains a collection of data structure definitions. The data structure definitions may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + GeographicCodelists contains a collection of geographi codelist descriptions. The codelists may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + GeoGridCodelists contains a collection of geographic grid codelist descriptions. The codelists may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + Hierarchies contains a collection of hierarchical code list descriptions. The hierarchical code lists may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + HierarchyAssociations contains a collection of hierarchy associations. The associations may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + MetadataConstraints contains a collection of metadata constraint descriptions. The constraints may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + Metadataflows contains a collection of metadata flow descriptions. The metadata flows may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + MetadataProviderSchemes contains a collection of metadata provider scheme descriptions. The meatadata provider schemes may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + ProvisionAgreements contains a collection of provision agreements. The provision agreements may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + MetadataStructures contains a collection of metadata structure definition descriptions. The metadata structure definitions may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + NamePersonalisationSchemes contains a collection of name personalisation schemes. The scheme may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + OrganisationSchemeMaps contains a collection of organisation scheme map descriptions. The organisation scheme maps may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + OrganisationUnitSchemes contains a collection of organisation unit scheme descriptions. The organisation unit schemes may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + Processes contains a collection of process descriptions. The processes may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + ProvisionAgreements contains a collection of provision agreements. The provision agreements may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + ReportingTaxonomies contains a collection of reporting taxonomy descriptions. The reporting taxonomies may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + ReportingTaxonomyMaps contains a collection of reporting taxonomy map descriptions. The reporting taxonomy maps may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + RepresentationMaps contains a collection of representation map descriptions. The representation maps may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + RulesetSchemes contains a collection of ruleset schemes. The scheme may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + StructureMaps contains a collection of structure map descriptions. The structure maps may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + TransformationSchemes contains a collection of transformation schemes. The transformation schemes may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + UserDefinedOperatorSchemes contains a collection of user defined operator schemes. The scheme may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + ValueLists contains a collection of value list descriptions. The value lists may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + VtlMappingSchemes contains a collection of VTL mapping schemes. The scheme may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + + + + AgencySchemesType describes the structure of the agency schemes container. It contains one or more agency scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + AgencyScheme provides the details of an agency scheme, in which agencies are described. + + + + + + + + + + + + CategorisationsType describes the structure of the categorisations container. It contains one or more categorisation of a specific object type, which can be explicitly detailed or referenced from an external structure document or registry service. This container may contain categorisations for multiple types of structural objects. + + + + + Categorisation allows for the association of an identifiable object to a category, providing for the classifications of the reference identifiable object. This must either contain the full details of the categorisation, or provide a name and identification information and reference the full details from an external structure document or registry service. + + + + + + + + CategorySchemeMapsType describes the structure of the category scheme maps container. It contains one or more category scheme map, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + CategorySchemeMap provides the details of a category scheme map, which descibes mappings between categories in different schemes. + + + + + + + + CategorySchemesType describes the structure of the category schemes container. It contains one or more category scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + CategoryScheme provides the details of a category scheme, which is the descriptive information for an arrangement or division of categories into groups based on characteristics, which the objects have in common. This provides for a simple, leveled hierarchy or categories. + + + + + + + + + + + + ConceptSchemeMapsType describes the structure of the concept scheme maps container. It contains one or more concept scheme map, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + ConceptSchemeMap provides the details of a concept scheme map, which descibes mappings between concepts in different schemes. + + + + + + + + ConceptSchemesType describes the structure of the concept schemes container. It contains one or more concept schemes, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + ConceptScheme provides the details of a concept scheme, which is the descriptive information for an arrangement or division of concepts into groups based on characteristics, which the objects have in common. It contains a collection of concept definitions, that may be arranged in simple hierarchies. + + + + + + + + + + + + CodelistsType describes the structure of the codelists container. It contains one or more codelist, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + Codelist provides the details of a codelist, which is defined as a list from which some statistical concepts (coded concepts) take their values. + + + + + + + + + + + + CustomTypeSchemesType describes the structure of the custom type schemes container. It contains one or more custom type scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + CustomTypeScheme provides the details of a custom type scheme, in which user defined operators are described. + + + + + + + + + + + + DataConstraintsType describes the structure of the data constraints container. It contains one or more data constraint, which can be explicitly detailed or referenced from an external structure document or registry service. This container may contain both attachment and content constraints. + + + + + DataConstraint specifies a sub set of the definition of the allowable or available content of a data set in terms of the content or in terms of the set of key combinations. + + + + + + + + + + + + DataConsumerSchemesType describes the structure of the data consumer schemes container. It contains one or more data consumer scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + DataConsumerScheme provides the details of an data consumer scheme, in which data consumers are described. + + + + + + + + + + + + DataflowsType describes the structure of the data flows container. It contains one or more data flow, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + Dataflow provides the details of a data flow, which is defined as the structure of data that will be provided for different reference periods. + + + + + + + + DataProviderSchemesType describes the structure of the data provider schemes container. It contains one or more data provider scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + DataProviderScheme provides the details of an data provider scheme, in which data providers are described. + + + + + + + + + + + + DataStructuresType describes the structure of the data structure definitions container. It contains one or more data structure definition, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + DataStructure provides the details of a data structure definition, which is defined as a collection of metadata concepts, their structure and usage when used to collect or disseminate data. + + + + + + + + GeographicCodelistsType describes the structure of the geographic code lists container. It contains one or more geographic codelist, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + GeographiCodelist provides the details of a geographic codelists container, which comprises a set of GeoFeatureSetCodes, by adding a value in the Code that follows a pattern to represent a geo feature set. + + + + + + + + + + + + GeoGridCodelistsType describes the structure of the codelists container. It contains one or more geographic grid codelist, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + GeoGridCodelist provides the details of a geographic grid code list, which comprises a set of GridCodes, which are related to the gridDefinition specified in the GeoGridCodelist. + + + + + + + + + + + + HierarchiesType describes the structure of the hierarchies container. It contains one or more hierarchy, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + Hierarchy provides the details of a hierarchy, which is defined as an organised collection of codes that may participate in many parent/child relationships with other codes in the list. + + + + + + + + + + + + + + + + HiearchyAssociationsType describes the structure of the hierarchy assoications container. It contains one or more hiearchy associations, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + HierarchyAssociation provides the details of a hiearchy assoication, which associates a hiearchy with an identifiable object in the context of another object. + + + + + + + + MetadataConstraintsType describes the structure of the metadata constraints container. It contains one or more metadata constraint, which can be explicitly detailed or referenced from an external structure document or registry service. This container may contain both attachment and content constraints. + + + + + MetadataConstraint specifies a sub set of the definition of the allowable content of a metadata set. + + + + + + + + + + + + MetadataflowsType describes the structure of the metadata flows container. It contains one or more metadata flow, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + Metadataflow provides the details of a metadata flow, which is defined as the structure of reference metadata that will be provided for different reference periods + + + + + + + + MetadataProviderSchemesType describes the structure of the metadata provider schemes container. It contains one or more metadata provider scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + MetadataProviderScheme provides the details of an metadata provider scheme, in which metadata providers are described. + + + + + + + + + + + + MetadataProvisionAgreementsType describes the structure of the metadata provision agreements container. It contains one or more metadata provision agreement, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + MetadataProvisionAgreement provides the details of a metadata provision agreement, which is an agreement for a metadata provider to report reference metadata against a flow. + + + + + + + + MetadataStructuresType describes the structure of the metadata structure definitions container. It contains one or more metadata structure definition, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + MetadataStructure provides the details of a metadata structure definition, which is defined as a collection of metadata concepts, their structure and usage when used to collect or disseminate reference metadata. A metadata structure definition performs several functions: it groups sets of objects into "targets" against which reference metadata may be reported. Targets define the structure of the reference metadata "keys" which identify specific types of reported metadata, and describe the valid values for populating the keys. Also, metadata structure definitions provide a presentational organization of concepts for reporting purposes. The structure of reference metadata is derived from this presentational structure. + + + + + + + + NamePersonalisationSchemesType describes the structure of the name personalisation schemes container. It contains one or more name personalisation scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + NamePersonalisationScheme provides the details of a name personalisation scheme, in which name personalisations are described. + + + + + + + + + + + + OrganisationSchemeMapsType describes the structure of the organisation scheme maps container. It contains one or more organisation scheme map, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + OrganisationSchemeMap provides the details of a organisation scheme map, which descibes mappings between organisations in different schemes. + + + + + + + + OrganisationUnitSchemesType describes the structure of the organisation unit schemes container. It contains one or more organisation unit scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + OrganisationUnitScheme provides the details of an organisation unit scheme, in which organisation units are described. + + + + + + + + + + + + ProcessesType describes the structure of the processes container. It contains one or more process, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + Process provides the details of a process, which is a scheme which defines or documents the operations performed on data in order to validate data or to derive new information according to a given set of rules. It is not meant to support process automation, but serves as a description of how processes occur. The primary use for this structural mechanism is the attachment of reference metadata regarding statistical processing. This must either contain the full details of the category scheme, or provide a name and identification information and reference the full details from an external structure document or registry service. + + + + + + + + + + + + + + + + ProvisionAgreementsType describes the structure of the provision agreements container. It contains one or more provision agreement, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + ProvisionAgreement provides the details of a provision agreement, which is an agreement for a data provider to report data against a flow. + + + + + + + + ReportingTaxonomiesType describes the structure of the reporting taxonomies container. It contains one or more reporting taxonomy, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + ReportingTaxonomy provides the details of a reporting taxonomy, which is a scheme which defines the composition structure of a data report where each component can be described by an independent data or metadata flow definition. + + + + + + + + + + + + ReportingTaxonomyMapsType describes the structure of the reporting taxonomy maps container. It contains one or reporting taxonomy map, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + ReportingTaxonomyMap provides the details of a reporting taxonomy map, which descibes mappings between reporting taxonomies. + + + + + + + + RepresentationMapsType describes the structure of the representation maps container. It contains one or more representation map, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + RepresentationMap provides the details of a represenation map, which describes mappings between various component represenations. + + + + + + + + RulesetSchemesType describes the structure of the ruleset schemes container. It contains one or more ruleset scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + RulesetScheme provides the details of a ruleset scheme, in which rulesets are described. + + + + + + + + + + + + StructureMapsType describes the structure of the structure maps container. It contains one or more structure maps, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + StructureMap provides the details or a structure map, which describes mapping between data structures or dataflows. + + + + + + + + + + + + + + + + TransformationSchemesType describes the structure of the transformations container. It contains one or more transformation schemes, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + TransformationScheme provides the details of a transformation scheme, in which transformations are described. + + + + + + + + + + + + UserDefinedOperatorSchemesType describes the structure of the user defined operator schemes container. It contains one or more user defined operator scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + UserDefinedOperatorScheme provides the details of a user defined operator scheme, in which user defined operators are described. + + + + + + + + + + + + ValueListsType describes the structure of the value lists container. It contains one or more value list, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + ValueList provides the details of a value list, which is a closed set of values that can occur for a dimension, measure, or attribute. This may be a simple list of values, or a list of values with names and descriptions (similar to a codelist). + + + + + + + + VtlMappingSchemesType describes the structure of the VTL mappings schemes container. It contains one or more VTL mapping schemes, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + VtlMappingScheme provides the details of a VTL mapping scheme, in which VTL mappings are described. + + + + + + + + + + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureBase.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureBase.xsd new file mode 100644 index 0000000..b34cf57 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureBase.xsd @@ -0,0 +1,486 @@ + + + + + + + SDMX Base Structure Module + The base structure module contains the descriptions of base structural metadata constructs, such as item schemes, structures, and structure usages, as well as constructs reused by multiple types of structural components. + + + + + ItemSchemeType is an abstract base type for all item scheme objects. It contains a collection of items. Concrete instances of this type should restrict the actual types of items allowed within the scheme. + + + + + + + + + + + The isPartial, if true, indicates that only the relevant portion of the item scheme is being communicated. This is used in cases where a codelist is returned for a data structure in the context of a constraint. + + + + + + + + + Item is an abstract element that serves as a substitution head for all items in an item scheme, including those items nested within other items. Concrete instances of this must use a concrete instance of ItemType. + + + + + + ItemBaseType is an abstract base type that forms the basis for the ItemType. It requires that at least an id be supplied for an item. + + + + + + + + + + + + + + + + + ItemType is an abstract base type for all items with in an item scheme. Concrete instances of this type may or may not utilize the nested item, but if so should restrict the actual types of item allowed. + + + + + + + + + + + + + + + + UnnestedItemType is an abstract base type for all items with in an item scheme that do not contain nested items. + + + + + + + + + + + + + + + + StructureType is an abstract base type for all structure objects. Concrete instances of this should restrict to a concrete grouping. + + + + + + + + + + + + + + + Grouping is an abstract element that serves as a substitution head for all structure groupings. Groupings contain a collection of component lists for a structure. Concrete instances of this must use a concrete instance of GroupingType. + + + + + + GroupType is an abstract base type for specific structure groupings. It contains a collection of component lists. Concrete instances of this should restrict to specific concrete component lists. + + + + + + + + + + + ComponentList is an abstract element that serves as a substitution head for all component lists. Concrete instances of this must use a concrete instance of ComponentListType. + + + + + + ComponentListType is an abstract base type for all component lists. It contains a collection of components. Concrete types should restrict this to specific concrete components. + + + + + + + + + + + + + + + Component is an abstract element that serves as a substitution head for all components. Concrete instances of this must use a concrete instance of ComponentType. + + + + + + ComponentBaseType is an abstract type that only serves the purpose of forming the base for the actual ComponentType. It only restricts the format of the id attribute to the NCNameIDType. + + + + + + + + + + The id attribute holds an explicit identification of the component. If this identifier is not supplied, then it is assumed to be the same as the identifier of the concept referenced from the concept identity. Because structures require that every component be given a unique identifier, it may be necessary to assign an explicit identifier when more than one component in a structure reference concepts with same identifier. It is important to note that this applies strictly to the identifier of concept and not the URN. Therefore if two concepts with the same identifier from different concept schemes are referenced in the same structure, one of the components will have to provide a unique explicit identifier. The type of this identifier is restricted to the common:NCNameIDType. This is necessary, since component identifiers are used to create XML elements and attributes in data and metadata structure specific schemas and therefore must be compliant with the NCName type in XML Schema (see common:NCNameIDType for further details). + + + + + + + + + ComponentType is an abstract base type for all components. It contains information pertaining to a component, including an optional reference to a concept, an optional role played by the concept, an optional text format description, and an optional local representation. + + + + + + + ConceptIdentity allows for the referencing of a concept in a concept scheme. The component takes its semantic from this concept, and if an id is not specified, it takes its identification as well. If a representation (LocalRepresentation) is not supplied, then the representation of the component is also inherited from the concept. Note that in the case of the component representation being inherited from the concept, the allowable representations for the component still apply. Therefore, if a component references a concept with a core representation that is not allowed for the concept, that representation must be locally overridden. For components which can specify a concept role, it is implied that the concept which is referenced also identifies a role for the component. + + + + + LocalRepresentation references item schemes that may be used to create the representation of a component. The type of this must be refined such that a concrete item scheme reference is used. + + + + + + + + + + StructureUsageType is an abstract base type for all structure usages. It contains a reference to a structure. Concrete instances of this type should restrict the type of structure referenced. + + + + + + + Structure references the structure (data structure or metadata structure definition) which the structure usage is based upon. Implementations will have to refine the type to use a concrete structure reference (i.e. either a data structure or metadata structure definition reference). + + + + + + + + + + RepresentationType is an abstract type that defines a representation. Because the type of item schemes that are allowed as the an enumeration vary based on the object in which this is defined, this type is abstract to force that the enumeration reference be restricted to the proper type of item scheme reference. + + + + + TextFormat describes an uncoded textual format. + + + + + + Enumeration references an item scheme that enumerates the allowable values for this representation. + + + + + EnumerationFormat describes the facets of the item scheme enumeration. This is for the most part, informational. + + + + + + + The minOccurs attribute indicates the minimum number of value that must be reported for the component. + + + + + The maxOccurs attribute indicates the maximum number of values that can be reported for the component. + + + + + + + TextFormatType defines the information for describing a full range of text formats and may place restrictions on the values of the other attributes, referred to as "facets". + + + + + SentinelValue defines a value that has a special meaning within the text format representation of a component. + + + + + + The textType attribute provides a description of the datatype. If it is not specified, any valid characters may be included in the text field (it corresponds to the xs:string datatype of W3C XML Schema) within the constraints of the facets. + + + + + The isSequence attribute indicates whether the values are intended to be ordered, and it may work in combination with the interval, startValue, and endValue attributes or the timeInterval, startTime, and endTime, attributes. If this attribute holds a value of true, a start value or time and a numeric or time interval must supplied. If an end value is not given, then the sequence continues indefinitely. + + + + + The interval attribute specifies the permitted interval (increment) in a sequence. In order for this to be used, the isSequence attribute must have a value of true. + + + + + The startValue attribute is used in conjunction with the isSequence and interval attributes (which must be set in order to use this attribute). This attribute is used for a numeric sequence, and indicates the starting point of the sequence. This value is mandatory for a numeric sequence to be expressed. + + + + + The endValue attribute is used in conjunction with the isSequence and interval attributes (which must be set in order to use this attribute). This attribute is used for a numeric sequence, and indicates that ending point (if any) of the sequence. + + + + + The timeInterval attribute indicates the permitted duration in a time sequence. In order for this to be used, the isSequence attribute must have a value of true. + + + + + The startTime attribute is used in conjunction with the isSequence and timeInterval attributes (which must be set in order to use this attribute). This attribute is used for a time sequence, and indicates the start time of the sequence. This value is mandatory for a time sequence to be expressed. + + + + + The endTime attribute is used in conjunction with the isSequence and timeInterval attributes (which must be set in order to use this attribute). This attribute is used for a time sequence, and indicates that ending point (if any) of the sequence. + + + + + The minLength attribute specifies the minimum and length of the value in characters. + + + + + The maxLength attribute specifies the maximum length of the value in characters. + + + + + The minValue attribute is used for inclusive and exclusive ranges, indicating what the lower bound of the range is. If this is used with an inclusive range, a valid value will be greater than or equal to the value specified here. If the inclusive and exclusive data type is not specified (e.g. this facet is used with an integer data type), the value is assumed to be inclusive. + + + + + The maxValue attribute is used for inclusive and exclusive ranges, indicating what the upper bound of the range is. If this is used with an inclusive range, a valid value will be less than or equal to the value specified here. If the inclusive and exclusive data type is not specified (e.g. this facet is used with an integer data type), the value is assumed to be inclusive. + + + + + The decimals attribute indicates the number of characters allowed after the decimal separator. + + + + + The pattern attribute holds any regular expression permitted in the similar facet in W3C XML Schema. + + + + + The isMultiLingual attribute indicates for a text format of type "string", whether the value should allow for multiple values in different languages. + + + + + + + SentinelValueType defines the structure of a sentinel value. A sentinel is a value that has a special meaning within the text format representation of a component. The value is associated with a multi-lingual name and description. + + + + + + + + The sentinel value being described. + + + + + + + BasicComponentTextFormatType is a restricted version of the TextFormatType that restricts the text type to the representations allowed for all components except for target objects. + + + + + + + + + + + + + + SimpleComponentTextFormatType is a restricted version of the BasicComponentTextFormatType that does not allow for multi-lingual values. + + + + + + + + + + + + + + + CodedTextFormatType is a restricted version of the SimpleComponentTextFormatType that only allows factets and text types applicable to codes. Although the time facets permit any value, an actual code identifier does not support the necessary characters for time. Therefore these facets should not contain time in their values. + + + + + + + + + + + + + + + + + + + + + + + + CodeDataType is a restriction of the basic data types that are applicable to codes. Although some of the higher level time period formats are perimitted, it should be noted that any value which contains time (which includes a time zone offset) is not allowable as a code identifier. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NonFacetedTextFormatType is a restricted version of the SimpleComponentTextFormatType that does not allow for any facets. + + + + + + + + + + + + + + + + + + + + + + + + TimeTextFormat is a restricted version of the SimpleComponentTextFormatType that only allows time based format and specifies a default ObservationalTimePeriod representation and facets of a start and end time. + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCL.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCL.xsd new file mode 100644 index 0000000..211d4a3 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCL.xsd @@ -0,0 +1,646 @@ + + + + + + + + + SDMX Structure Namespace Module + The structure namespace module contains the descriptions of structural metadata such as key families, concepts, and codelists. For convenience, this module has been broken down into sub-modules for the different type of structural constructs. + + + + + Structures contains constructs for all structural metadata components. + + + + + + StructuresType describes the structure of the container for all structural metadata components. The structural components may be explicitly detailed, or referenced from an external structure document or registry service. Best practices dictate that, at a minimum, any structural component that is referenced by another structural component be included by reference. + + + + + Codelists contains a collection of code list descriptions. The code lists may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + + + + UserDefinedOperatorSchemes contains a collection of user defined operator schemes. The scheme may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + ValueLists contains a collection of value list descriptions. The value lists may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + VtlMappingSchemes contains a collection of VTL mapping schemes. The scheme may be detailed in full, or referenced from an external structure document or registry service. + + + + + + + + + + + + + + AgencySchemesType describes the structure of the agency schemes container. It contains one or more agency scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + AgencyScheme provides the details of an agency scheme, in which agencies are described. + + + + + + + + + + + + CategorisationsType describes the structure of the categorisations container. It contains one or more categorisation of a specific object type, which can be explicitly detailed or referenced from an external structure document or registry service. This container may contain categorisations for multiple types of structural objects. + + + + + Categorisation allows for the association of an identifiable object to a category, providing for the classifications of the reference identifiable object. This must either contain the full details of the categorisation, or provide a name and identification information and reference the full details from an external structure document or registry service. + + + + + + + + CategorySchemeMapsType describes the structure of the category scheme maps container. It contains one or more category scheme map, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + CategorySchemeMap provides the details of a category scheme map, which descibes mappings between categories in different schemes. + + + + + + + + CategorySchemesType describes the structure of the category schemes container. It contains one or more category scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + CategoryScheme provides the details of a category scheme, which is the descriptive information for an arrangement or division of categories into groups based on characteristics, which the objects have in common. This provides for a simple, leveled hierarchy or categories. + + + + + + + + + + + + ConceptSchemeMapsType describes the structure of the concept scheme maps container. It contains one or more concept scheme map, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + ConceptSchemeMap provides the details of a concept scheme map, which descibes mappings between concepts in different schemes. + + + + + + + + ConceptSchemesType describes the structure of the concept schemes container. It contains one or more concept schemes, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + ConceptScheme provides the details of a concept scheme, which is the descriptive information for an arrangement or division of concepts into groups based on characteristics, which the objects have in common. It contains a collection of concept definitions, that may be arranged in simple hierarchies. + + + + + + + + + + + + CodelistsType describes the structure of the codelists container. It contains one or more codelist, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + Codelist provides the details of a codelist, which is defined as a list from which some statistical concepts (coded concepts) take their values. + + + + + + + + + + + + CustomTypeSchemesType describes the structure of the custom type schemes container. It contains one or more custom type scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + CustomTypeScheme provides the details of a custom type scheme, in which user defined operators are described. + + + + + + + + + + + + DataConstraintsType describes the structure of the data constraints container. It contains one or more data constraint, which can be explicitly detailed or referenced from an external structure document or registry service. This container may contain both attachment and content constraints. + + + + + DataConstraint specifies a sub set of the definition of the allowable or available content of a data set in terms of the content or in terms of the set of key combinations. + + + + + + + + + + + + DataConsumerSchemesType describes the structure of the data consumer schemes container. It contains one or more data consumer scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + DataConsumerScheme provides the details of an data consumer scheme, in which data consumers are described. + + + + + + + + + + + + DataflowsType describes the structure of the data flows container. It contains one or more data flow, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + Dataflow provides the details of a data flow, which is defined as the structure of data that will be provided for different reference periods. + + + + + + + + DataProviderSchemesType describes the structure of the data provider schemes container. It contains one or more data provider scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + DataProviderScheme provides the details of an data provider scheme, in which data providers are described. + + + + + + + + + + + + DataStructuresType describes the structure of the data structure definitions container. It contains one or more data structure definition, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + DataStructure provides the details of a data structure definition, which is defined as a collection of metadata concepts, their structure and usage when used to collect or disseminate data. + + + + + + + + GeographicCodelistsType describes the structure of the geographic code lists container. It contains one or more geographic codelist, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + GeographiCodelist provides the details of a geographic codelists container, which comprises a set of GeoFeatureSetCodes, by adding a value in the Code that follows a pattern to represent a geo feature set. + + + + + + + + + + + + GeoGridCodelistsType describes the structure of the codelists container. It contains one or more geographic grid codelist, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + GeoGridCodelist provides the details of a geographic grid code list, which comprises a set of GridCodes, which are related to the gridDefinition specified in the GeoGridCodelist. + + + + + + + + + + + + HierarchiesType describes the structure of the hierarchies container. It contains one or more hierarchy, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + Hierarchy provides the details of a hierarchy, which is defined as an organised collection of codes that may participate in many parent/child relationships with other codes in the list. + + + + + + + + + + + + + + + + HiearchyAssociationsType describes the structure of the hierarchy assoications container. It contains one or more hiearchy associations, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + HierarchyAssociation provides the details of a hiearchy assoication, which associates a hiearchy with an identifiable object in the context of another object. + + + + + + + + MetadataConstraintsType describes the structure of the metadata constraints container. It contains one or more metadata constraint, which can be explicitly detailed or referenced from an external structure document or registry service. This container may contain both attachment and content constraints. + + + + + MetadataConstraint specifies a sub set of the definition of the allowable content of a metadata set. + + + + + + + + + + + + MetadataflowsType describes the structure of the metadata flows container. It contains one or more metadata flow, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + Metadataflow provides the details of a metadata flow, which is defined as the structure of reference metadata that will be provided for different reference periods + + + + + + + + MetadataProviderSchemesType describes the structure of the metadata provider schemes container. It contains one or more metadata provider scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + MetadataProviderScheme provides the details of an metadata provider scheme, in which metadata providers are described. + + + + + + + + + + + + MetadataProvisionAgreementsType describes the structure of the metadata provision agreements container. It contains one or more metadata provision agreement, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + MetadataProvisionAgreement provides the details of a metadata provision agreement, which is an agreement for a metadata provider to report reference metadata against a flow. + + + + + + + + MetadataStructuresType describes the structure of the metadata structure definitions container. It contains one or more metadata structure definition, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + MetadataStructure provides the details of a metadata structure definition, which is defined as a collection of metadata concepts, their structure and usage when used to collect or disseminate reference metadata. A metadata structure definition performs several functions: it groups sets of objects into "targets" against which reference metadata may be reported. Targets define the structure of the reference metadata "keys" which identify specific types of reported metadata, and describe the valid values for populating the keys. Also, metadata structure definitions provide a presentational organization of concepts for reporting purposes. The structure of reference metadata is derived from this presentational structure. + + + + + + + + NamePersonalisationSchemesType describes the structure of the name personalisation schemes container. It contains one or more name personalisation scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + NamePersonalisationScheme provides the details of a name personalisation scheme, in which name personalisations are described. + + + + + + + + + + + + OrganisationSchemeMapsType describes the structure of the organisation scheme maps container. It contains one or more organisation scheme map, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + OrganisationSchemeMap provides the details of a organisation scheme map, which descibes mappings between organisations in different schemes. + + + + + + + + OrganisationUnitSchemesType describes the structure of the organisation unit schemes container. It contains one or more organisation unit scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + OrganisationUnitScheme provides the details of an organisation unit scheme, in which organisation units are described. + + + + + + + + + + + + ProcessesType describes the structure of the processes container. It contains one or more process, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + Process provides the details of a process, which is a scheme which defines or documents the operations performed on data in order to validate data or to derive new information according to a given set of rules. It is not meant to support process automation, but serves as a description of how processes occur. The primary use for this structural mechanism is the attachment of reference metadata regarding statistical processing. This must either contain the full details of the category scheme, or provide a name and identification information and reference the full details from an external structure document or registry service. + + + + + + + + + + + + + + + + ProvisionAgreementsType describes the structure of the provision agreements container. It contains one or more provision agreement, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + ProvisionAgreement provides the details of a provision agreement, which is an agreement for a data provider to report data against a flow. + + + + + + + + ReportingTaxonomiesType describes the structure of the reporting taxonomies container. It contains one or more reporting taxonomy, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + ReportingTaxonomy provides the details of a reporting taxonomy, which is a scheme which defines the composition structure of a data report where each component can be described by an independent data or metadata flow definition. + + + + + + + + + + + + ReportingTaxonomyMapsType describes the structure of the reporting taxonomy maps container. It contains one or reporting taxonomy map, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + ReportingTaxonomyMap provides the details of a reporting taxonomy map, which descibes mappings between reporting taxonomies. + + + + + + + + RepresentationMapsType describes the structure of the representation maps container. It contains one or more representation map, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + RepresentationMap provides the details of a represenation map, which describes mappings between various component represenations. + + + + + + + + RulesetSchemesType describes the structure of the ruleset schemes container. It contains one or more ruleset scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + RulesetScheme provides the details of a ruleset scheme, in which rulesets are described. + + + + + + + + + + + + StructureMapsType describes the structure of the structure maps container. It contains one or more structure maps, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + StructureMap provides the details or a structure map, which describes mapping between data structures or dataflows. + + + + + + + + + + + + + + + + TransformationSchemesType describes the structure of the transformations container. It contains one or more transformation schemes, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + TransformationScheme provides the details of a transformation scheme, in which transformations are described. + + + + + + + + + + + + UserDefinedOperatorSchemesType describes the structure of the user defined operator schemes container. It contains one or more user defined operator scheme, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + UserDefinedOperatorScheme provides the details of a user defined operator scheme, in which user defined operators are described. + + + + + + + + + + + + ValueListsType describes the structure of the value lists container. It contains one or more value list, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + ValueList provides the details of a value list, which is a closed set of values that can occur for a dimension, measure, or attribute. This may be a simple list of values, or a list of values with names and descriptions (similar to a codelist). + + + + + + + + VtlMappingSchemesType describes the structure of the VTL mappings schemes container. It contains one or more VTL mapping schemes, which can be explicitly detailed or referenced from an external structure document or registry service. + + + + + VtlMappingScheme provides the details of a VTL mapping scheme, in which VTL mappings are described. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCategorisation.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCategorisation.xsd new file mode 100644 index 0000000..62051da --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCategorisation.xsd @@ -0,0 +1,51 @@ + + + + + + + + SDMX Categorisation Structure Module + The categorisation structure module defines the structure categorisation constructs. + + + + + CategorisationBaseType defines the base refinement of the CategorisationType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + CategorisationType is defines the structure for a categorisation. A source object is referenced via an object reference and the target category is referenced via the target category. + + + + + + + Source is a reference to an object to be categorized. + + + + + Target is reference to the category that the referenced object is to be mapped to. + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCategory.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCategory.xsd new file mode 100644 index 0000000..1abab74 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCategory.xsd @@ -0,0 +1,69 @@ + + + + + + + + SDMX Category Structure Module + The category structure module defines the structure of category scheme and category constructs. + + + + + CategorySchemeType describes the structure of a category scheme. A category scheme is the descriptive information for an arrangement or division of categories into groups based on characteristics, which the objects have in common. This provides for a simple, leveled hierarchy or categories. + + + + + + + + + + + + + + + + The id attribute holds the identification of the category scheme. The type of this id is restricted to the common:NCNNameIDType. This is necessary, since the category scheme may be used to create simple types in data and metadata structure specific schemas and therefore must be compliant with the NCName type in XML Schema (see common:NCNameIDType for further details). + + + + + + + + + Category represents a set of nested categories which describe a simple classification hierarchy. + + + + + + + + + + CategoryType describes the details of a category. A category is defined as an item at any level in a classification. The Category element represents a set of nested categories which are child categories. + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCodelist.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCodelist.xsd new file mode 100644 index 0000000..deca008 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureCodelist.xsd @@ -0,0 +1,365 @@ + + + + + + + + SDMX Code List Structure Module + The code list structure module defines the structure of code list and code constructs. + + + + + CodelistType defines the structure of a codelist. A codelist is defined as a list from which some statistical concepts (coded concepts) take their values. + + + + + + + + + + + + + + + + The id attribute holds the identification of the code list. The type of this id is restricted to the common:NCNNameIDType. This is necessary, since the code list may be used to create simple types in data and metadata structure specific schemas and therefore must be compliant with the NCName type in XML Schema (see common:NCNameIDType for further details). + + + + + + + + + + + + + CodelistExtension allows for the extension of codelists by referencing the codelists to be extended and providing inclusion/exclusion rules for selecting the codes to extend. The order of these is important as it is indicates the order of precedence of the extended codelists for conflict resolution of codes. However, the prefix property can be used to ensure uniqueness of inherited codes in the extending codelist, in case conflicting codes must be included. + + + + + + + + + + Code describes a code in a codelist. In addition to the identification and description of the code, basic presentational information is also available. Presentational information not present may be added through the use of annotations. + + + + + + CodeType describes the structure of a code. A code is defined as a language independent set of letters, numbers or symbols that represent a concept whose meaning is described in a natural language. Presentational information not present may be added through the use of annotations. + + + + + + + + + Name provides for a human-readable name for the object. This may be provided in multiple, parallel language-equivalent forms. It may be used in place of a short description. + + + + + Description provides a plain text, human-readable description of the code. This may be provided in multiple, parallel language-equivalent forms. + + + + + + Parent provides the ability to describe simple hierarchies within a single codelist, by referencing the id value of another code in the same codelist. + + + + + + + + + + + + CodelistExtensionType defines the structure of a codelist to be extended by the codelist defining the extension. It provides a reference to the extended codelist and selection criteria to indicate the codes to be included in the extending codelist. + + + + + + + Selection of codes from the referenced (extended) codelist to be included in the extending codelist. + + + + + Selection of codes from the referenced (extended) codelist to be excluded in the extending codelist. + + + + + + + A reference to a codelist may contain a prefix. If a prefix is provided, this prefix will be applied to all the codes in the codelist before they are imported into the extended codelist. + + + + + + + CodeSelectionType defines the structure for code selection to be used as inclusive or exclusive extensions. + + + + + An explicit or wildcard selection of a code(s) from the codelist selected for inclusion/exclusion. If a wildcard expression is used, it is evaluated to determine codes selected for inclusion/exclusion. Otherwise, each member value is a distinct code. If the extended list is hierarchical, this can indicate whether child codes are to be included. + + + + + + + + + WildcardedMemberValueType allows for an optional wildcard characters ('%') in an identifier. + + + + + + + + + Allows for a ditinct reference or a wildcard expression for selecting codes from a codelist. + + + + + + Indicates whether child codes should be selected when the codelist is hierarchical. Possible values are true (include the selected and child codes), false (only include the selected code(s)), and excluderoot (include the children but not the selected code(s)). + + + + + + + + + GeoCodelistBaseType is an abstract base refinement of a codelist that restricts the cods to be derived from the abstract GeoRefCode. + + + + + + + + + + + + + + + + + + + + GeoCodelistType is an abstract refinement of a codelist from which specific types of geographic codelists will be derived. + + + + + + The type of geographic codelist. The will be refined and provided a fixed value in the specific geographic codelist type implementations. + + + + + + + + + GeoRefCode is the abstract base from which specific types of geographic codes will be derived. + + + + + + GeoRefCodeType is the abstract base type defining the structure of geographic codes. + + + + + + + + + GeographicCodelistType defines the sturcture of a geographic codelist. It comprises a set of GeoFeatureSetCodes, by adding a value in the Code that follows a pattern to represent a geo feature set. + + + + + + + + + + + + + + + + + + + + + Is a geographic code in a geographic codelist. It adds a value to a code that folows a pattern to represent a geo feature set. + + + + + + GeoFeatureSetCodeType defines the structure of a geogrphic code. + + + + + + The geo feature set of the Code, which represents a set of points defining a feature in a format defined a predefined pattern (see section 6). + + + + + + + + + GeoGridCodelistBaseType is the abstract base refinement for a geographic grid codelist. + + + + + + + + + + + + + + + + + + + + + GeoGridCodelistType defines the structure of a geographic grid code list. These define a geographical grid composed of cells representing regular squared portions of the Earth. + + + + + + + Contains a regular expression string corresponding to the grid definition for the GeoGrid Codelist. + + + + + + + + + + GeoGridCode is a code the represents a geographic grid cell that belongs to a specific grid definition. + + + + + + GeoGridCodeType defines the structure of a geographic grid cell. + + + + + + + The value used to assign the Code to one cell in the grid. + + + + + + + + + + GeoCodelistTypeType defines an enumeration of the speicfic types of geographic codelists. + + + + + + + + + + ValueListBaseType defines the base refinement of the ValueListType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + ValueListType defines the structure of value list. These represent a closed set of values the can occur for a dimension, measure, or attribute. These may be values, or values with names and descriptions (similar to a codelist). + + + + + + + + + + + + + + + + + ValueItemType defines the structure of a value item. A value must be provided, and a longer name and description can be provided to provide additiona meaning to the value (similar to a code in a code list). + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureConcept.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureConcept.xsd new file mode 100644 index 0000000..ca72cc8 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureConcept.xsd @@ -0,0 +1,126 @@ + + + + + + + + SDMX Concept Structure Module + The concept structure module defines the structure of concept scheme and concept constructs. + + + + + ConceptSchemeType describes the structure of a concept scheme. A concept scheme is the descriptive information for an arrangement or division of concepts into groups based on characteristics, which the objects have in common. It contains a collection of concept definitions, that may be arranged in simple hierarchies. + + + + + + + + + + + + + + + + The id attribute holds the identification of the concept scheme. The type of this id is restricted to the common:NCNNameIDType. This is necessary, since the concept scheme may be used to create simple types in data and metadata structure specific schemas and therefore must be compliant with the NCName type in XML Schema (see common:NCNameIDType for further details). + + + + + + + + + Concept describes the details of a concept within a concept scheme. + + + + + + ConceptBaseType is an abstract base type the forms the basis of the ConceptType by requiring a name and id, and restricting the content of the id. + + + + + + + + + + + + Parent captures the semantic relationships between concepts which occur within a single concept scheme. This identifies the concept of which the current concept is a qualification (in the ISO 11179 sense) or subclass. + + + + + + + + The id attribute holds the identification of the concept. The type of this id is restricted to the common:NCNNameIDType. This is necessary, since concept id may be used to create XML elements and attributes in data and metadata structure specific schemas and therefore must be compliant with the NCName type in XML Schema (see common:NCNameIDType for further details). + + + + + + + + + ConceptType describes the details of a concept. A concept is defined as a unit of knowledge created by a unique combination of characteristics. If a concept does not specify a TextFormat or a core representation, then the representation of the concept is assumed to be represented by any set of valid characters (corresponding to the xs:string datatype of W3C XML Schema). + + + + + + + + + + + + Provides a reference to an ISO 11179 concept. + + + + + + + + + + ConceptRepresentation defines the core representation that are allowed for a concept. The text format allowed for a concept is that which is allowed for any non-target object component. + + + + + + + + + Enumeration references a codelist which enumerates the possible values that can be used as the representation of this concept. + + + + + + + + + + + + ISOConceptReferenceType provides a reference to and ISO 11179 concept. + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureConstraint.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureConstraint.xsd new file mode 100644 index 0000000..a11dad1 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureConstraint.xsd @@ -0,0 +1,765 @@ + + + + + + + + + SDMX Constraint Structure Module + The constraint structure module defines the structure of data and metadata constraint constructs. + + + + + ConstraintBaseType is an abstract base type that forms the basis of the main abstract ConstraintType. It requires that a name be provided. + + + + + + + + + + + + + + + + ConstraintType is an abstract base type that specific types of constraints (data and metadata) restrict and extend to describe their details. These constraint types both define a constraint attachment and a release calendar. + + + + + + + ConstraintAttachment describes the collection of constrainable artefacts that the constraint is attached to. + + + + + ReleaseCalendar defines dates on which the constrained data is to be made available. + + + + + + The role attribute indicates whether this constraint states what data is actually present for the constraint attachment, or if it defines what content is allowed. + + + + + + + + + DataConstraintBaseType is an abstract base refinement of ConstraintType. The constraint attachment is restricted to constrainable artefacts related to data. + + + + + + + + + + + + + + + + + + + DataConstraintType defines the structure of a data constraint. A data constraint can specify either the available set of keys (DataKeySet) or set of component values (CubeRegion) in a data source, or the allowable keys that can be constructed from a data structure definition. Multiple such constraints may be present for a constrained artefact. For instance, there may be a constraing that specifies the values allowed for the data source (role is "Allowed") which can be used for validation or for constructing a partial code list, whilst another constraing can specify the actual content of a data source (role is "Actual"). + + + + + + + DataKeySet defines a full, distinct set of dimension values and the attribute values associated with the key. + + + + + CubeRegion defines a slice of the data set (dimensions and attribute values) for the constrained artefact. A set of included or excluded regions can be described. + + + + + + + + + + MetadataConstraintBaseType is an abstract base refinement of ConstraintType. The constraint attachment is restricted to constrainable artefacts related to metadata, and the only possible role is "Allowed". + + + + + + + + + + + + + + + + + + + + MetadataConstraintType defines the structure of a metadata constraint. A metadata constraint can specify allowed attribute values for metadata described by the constrained artefact. + + + + + + + MetadataTargetRegion describes the values allowed for metadata attributes. + + + + + + + + + + ReleaseCalendarType describes information about the timing of releases of the constrained data. All of these values use the standard "P7D" - style format. + + + + + Periodicity is the period between releases of the data set. + + + + + Offset is the interval between January first and the first release of data within the year. + + + + + Tolerance is the period after which the release of data may be deemed late. + + + + + + + + DataKeySetType defines a collection of full or partial data keys (dimension values). + + + + + Key contains a set of dimension values which identify a full set of data. + + + + + + The isIncluded attribute indicates whether the keys defined in this key set are inclusive or exclusive to the constraint. + + + + + + + ConstraintAttachmentType describes a collection of references to constrainable artefacts. + + + + + DataProvider is reference to a data provider to which the constraint is attached. If this is used, then only the release calendar is relevant. The referenced is provided as a URN and/or a full set of reference fields. + + + + + MetadataProvider is reference to a metadata provider to which the constraint is attached. If this is used, then only the release calendar is relevant. The referenced is provided as a URN and/or a full set of reference fields. + + + + + MetadataSet is reference to a metadata set to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. + + + + + SimpleDataSource describes a simple data source, which is a URL of a SDMX-ML data or metadata message. + + + + + + + DataStructure is reference to a data structure definition to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. A constraint which is attached to more than one data structure must only express key sets and/or cube regions where the identifiers of the dimensions are common across all structures to which the constraint is attached. + + + + + QueryableDataSource describes a queryable data source to which the constraint is attached. + + + + + + + MetadataStructure is reference to a metadata structure definition to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. A constraint which is attached to more than one metadata structure must only express key sets and/or target regions where the identifiers of the target objects are common across all structures to which the constraint is attached. + + + + + QueryableDataSource describes a queryable data source to which the constraint is attached. + + + + + + + Dataflow is reference to a data flow to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. A constraint can be attached to more than one dataflow, and the dataflows do not necessarily have to be usages of the same data structure. However, a constraint which is attached to more than one data structure must only express key sets and/or cube regions where the identifiers of the dimensions are common across all structures to which the constraint is attached. + + + + + QueryableDataSource describes a queryable data source to which the constraint is attached. + + + + + + + Metadataflow is reference to a metadata flow to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. A constraint can be attached to more than one metadataflow, and the metadataflows do not necessarily have to be usages of the same metadata structure. However, a constraint which is attached to more than one metadata structure must only express key sets and/or target regions where the identifiers of the target objects are common across all structures to which the constraint is attached. + + + + + QueryableDataSource describes a queryable data source to which the constraint is attached. + + + + + + + ProvisionAgreementReference is reference to a provision agreement to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. A constraint can be attached to more than one provision aggreement, and the provision agreements do not necessarily have to be references structure usages based on the same structure. However, a constraint which is attached to more than one provision agreement must only express key sets and/or cube/target regions where the identifier of the components are common across all structures to which the constraint is attached. + + + + + QueryableDataSource describes a queryable data source to which the constraint is attached. + + + + + + + ProvisionAgreementReference is reference to a provision agreement to which the constraint is attached. The referenced is provided as a URN and/or a full set of reference fields. A constraint can be attached to more than one provision aggreement, and the provision agreements do not necessarily have to be references structure usages based on the same structure. However, a constraint which is attached to more than one provision agreement must only express key sets and/or cube/target regions where the identifier of the components are common across all structures to which the constraint is attached. + + + + + QueryableDataSource describes a queryable data source to which the constraint is attached. + + + + + + + + + + DataConstraintAttachmentType restricts the base ConstraintAttachmentType to only allow artefacts related to data. + + + + + + + + + + + + + + + + + + + + + + + + + + + + MetadataConstraintAttachmentType restricts the base ConstraintAttachmentType to only allow artefacts related to metadata. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ConstraintRoleType defines a list of roles for a content constraint. A constraint can state which data is present or which content is allowed for the constraint attachment. + + + + + The constraint contains the allowed values for attachable object. + + + + + The constraints contains the actual data present for the attachable object. + + + + + + + + RegionType is an abstract type which defines a generic constraint region. This type can be refined to define regions for data or metadata sets. A region is defined by a collection of key values - each of which a collection of values for a component which disambiguates data (i.e. dimensions of a dataset). For each region, a collection of attribute values can be provided. Taken together, the key values and attributes serve to identify or describe a subset of a data or metadata set. Finally, the region can flagged as being included or excluded, although this flag only makes sense when the region is used in a particular context. + + + + + + + KeyValue contains a reference to a component which disambiguates the data (i.e. a dimension) and provides a collection of values for the component. The collection of values can be flagged as being inclusive or exclusive to the region being defined. Any key component that is not included is assumed to be wild carded, which is to say that the cube includes all possible values for the un-referenced key components. Further, this assumption applies to the values of the components as well. The values for any given component can only be sub-setted in the region by explicit inclusion or exclusion. For example, a dimension X which has the possible values of 1, 2, 3 is assumed to have all of these values if a key value is not defined. If a key value is defined with an inclusion attribute of true and the values of 1 and 2, the only the values of 1 and 2 for dimension X are included in the definition of the region. If the key value is defined with an inclusion attribute of false and the value of 1, then the values of 2 and 3 for dimension X are included in the definition of the region. Note that any given key component must only be referenced once in the region. + + + + + Component contains a reference to a component (data attribute, metadata attribute, or measure) and provides a collection of values for the referenced component. This serves to state that for the key which defines the region, the components that are specified here have or do not have (depending on the include attribute of the value set) the values provided. It is possible to provide a component reference without specifying values, for the purpose of stating the component is absent (include = false) or present with an unbounded set of values. As opposed to key components, which are assumed to be wild carded if absent, no assumptions are made about the absence of a component. Only components which are explicitly stated to be present or absent from the region will be know. All unstated components for the set cannot be assumed to absent or present. + + + + + + The include attribute indicates that the region is to be included or excluded within the context in which it is defined. For example, if the regions is defined as part of a content constraint, the exclude flag would mean the data identified by the region is not present. + + + + + + + + + + + MemberSelectionType is an abstract base type which is used to provide a set of values for a referenced component. Implementations of this type will be based on a particular component type and refine the allowed values to reflect the types of values that are possible for that type of component. + + + + + Value provides a simple value for the component, such as a coded, numeric, or simple text value. This type of component value is applicable for dimensions and attributes. + + + + + TimeValue provides a value for a component which has a time representation. This is repeatable to allow for a range to be specified, although a single value can also be provided. An operator is available on this to indicate whether the specified value indicates an exact value or the beginning/end of a range (inclusive or exclusive). + + + + + + The id attribute provides the identifier for the component for which values are being provided. This base type allows for a nested identifier to be provided, for the purpose of referencing a nested component (i.e. a metadata attribute). However, specific implementations will restrict this representation to only allow single level identifiers where appropriate. + + + + + The include attribute indicates whether the values provided for the referenced component are to be included or excluded from the region in which they are defined. + + + + + The removePrefix attribute indicates whether codes should keep or not the prefix, as defined in the extension of codelist. + + + + + + + + + DataKeyType is a region which defines a distinct full or partial data key. The key consists of a set of values, each referencing a dimension and providing a single value for that dimension. The purpose of the key is to define a subset of a data set (i.e. the observed value and data attribute) which have the dimension values provided in this definition. Any dimension not stated explicitly in this key is assumed to be wild carded, thus allowing for the definition of partial data keys. + + + + + + + + + + + The include attribute has a fixed value of true for a distinct key, since such a key is always assumed to identify existing data or metadata. + + + + + + + + + DataKeyValueType is a type for providing a dimension value for the purpose of defining a distinct data key. Only a single value can be provided for the dimension. + + + + + + + + + + + + + + + + + DataComponentValueSetType defines the structure for providing values for a data attributes, measures, or metadata attributes. If no values are provided, the component is implied to include/excluded from the region in which it is defined, with no regard to the value of the component. Note that for metadata attributes which occur within other metadata attributes, a nested identifier can be provided. For example, a value of CONTACT.ADDRESS.STREET refers to the metadata attribute with the identifier STREET which exists in the ADDRESS metadata attribute in the CONTACT metadata attribute, which is defined at the root of the report structure. + + + + + + + + + + + + + + + + + CubeRegionType defines the structure of a data cube region. This is based on the abstract RegionType and simply refines the key and attribute values to conform with what is applicable for dimensions and attributes, respectively. See the documentation of the base type for more details on how a region is defined. + + + + + + + + + + + + + + + + + MetadataTargetRegionType defines the structure of a metadata target region. A metadata target region must define the report structure and the metadata target from that structure on which the region is based. This type is based on the abstract RegionType and simply refines the key and attribute values to conform with what is applicable for target objects and metadata attributes, respectively. See the documentation of the base type for more details on how a region is defined. + + + + + + + + + + + + + CubeRegionKeyType is a type for providing a set of values for a dimension for the purpose of defining a data cube region. A set of distinct value can be provided, or if this dimension is represented as time, and time range can be specified. + + + + + + + + + + + + + + + ComponentValueSetType defines the structure for providing values for a data attributes, measures, or metadata attributes. If no values are provided, the component is implied to include/excluded from the region in which it is defined, with no regard to the value of the component. Note that for metadata attributes which occur within other metadata attributes, a nested identifier can be provided. For example, a value of CONTACT.ADDRESS.STREET refers to the metadata attribute with the identifier STREET which exists in the ADDRESS metadata attribute in the CONTACT metadata attribute, which is defined at the root of the report structure. + + + + + + + + + + + + + + + + + MetadataAttributeValueSetType defines the structure for providing values for a metadata attribute. If no values are provided, the attribute is implied to include/excluded from the region in which it is defined, with no regard to the value of the metadata attribute. + + + + + + + + + + + + + + + + SimpleValueType contains a simple value for a component, and if that value is from a code list, the ability to indicate that child codes in a simple hierarchy are part of the value set of the component for the region. + + + + + + The cascadeValues attribute, if true, indicates that if the value is taken from a code all child codes in a simple hierarchy are understood be included in the region. + + + + + The xml:lang attribute specifies a language code for the value. This is used when the component value support multi-lingual values. + + + + + + + + + + + CubeKeyValueType derives from the SimpleValueType, but does not allow for a locale (xml:lang). + + + + + + + + + + + DataComponentValueType derives from the SimpleValueType, but does not allow for validity dates. + + + + + + + + + + + + SimpleKeyValueType derives from the SimpleValueType, but does not allow for the cascading of value in the hierarchy, as keys are meant to describe a distinct full or partial key. + + + + + + + + + + + + + + TimeRangeValueType allows a time period value to be expressed as a range. It can be expressed as the period before a period, after a period, or between two periods. Each of these properties can specify their inclusion in regards to the range. + + + + + BeforePeriod is the period before which the period is meant to cover. This date may be inclusive or exclusive in the range. + + + + + AfterPeriod is the period after which the period is meant to cover. This date may be inclusive or exclusive in the range. + + + + + + StartPeriod is the start date or the range that the queried date must occur within. This date may be inclusive or exclusive in the range. + + + + + EndPeriod is the end period of the range. This date may be inclusive or exclusive in the range. + + + + + + + + + + + TimePeriodRangeType defines a time period, and indicates whether it is inclusive in a range. + + + + + + The isInclusive attribute, when true, indicates that the time period specified is included in the range. + + + + + + + + + SimpleOperatorType provides an enumeration of simple operators to be applied to any value. + + + + + (!=) - value must not be equal to the value supplied. + + + + + (=) - value must be exactly equal to the value supplied. + + + + + + + + RangeOperatorType provides an enumeration of range operators to be applied to an ordered value. + + + + + (>=) - value must be greater than or equal to the value supplied. + + + + + (<=) - value must be less than or equal to the value supplied. + + + + + (>) - value must be greater than the value supplied. + + + + + (<) - value must be less than the value supplied. + + + + + + + + TextSearchOperatorType provides an enumeration of text search operators. + + + + + The text being searched must contain the supplied text. + + + + + The text being searched must start with the supplied text. + + + + + The text being searched must end with the supplied text. + + + + + The text being searched cannot contain the supplied text. + + + + + The text being searched cannot start with the supplied text. + + + + + The text being searched cannot end with the supplied text. + + + + + + + + OrderedOperatorType combines the SimpleOperatorType and the RangeOperatorType to provide a full range or operators for any ordered value. + + + + + + + + + + + + + + TimeOperatorType derives from the OrderedOperatorType to remove the notEqual operator. + + + + + + + + + + + diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureDataStructure.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureDataStructure.xsd new file mode 100644 index 0000000..7f451fa --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureDataStructure.xsd @@ -0,0 +1,638 @@ + + + + + + + + SDMX Data Structure Structure Module + The Data Structure structure module defines the structure of data structure definition constructs. + + + + + DataStructureBaseType describes base refinement of the StructureType for a data structure definition. A data structure definition is defined as a collection of metadata concepts, their structure and usage when used to collect or disseminate data. + + + + + + + + + + + + + + + + + + + + DataStructureType defines the structure for a data structure definition. A data structure definition is defined as a collection of metadata concepts, their structure and usage when used to collect or disseminate data. + + + + + + + A data structure definition may be related to a metadata structure definition in order to use its metadata attributes as part of the data. Note that the referenced metadata set cannot contain nested metadata attributes, as these are not supported in the data. By default all metadata attributes can be associated at any level of the data. However, a metadata attribute usage can be used to provide a specific attribute relationshp for a given metadata attribute. + + + + + + + + + + DataStructureComponents defines the grouping of the sets of metadata concepts that have a defined structural role in the data structure definition. Note that for any component or group defined in a data structure definition, its id must be unique. This applies to the identifiers explicitly defined by the components as well as those inherited from the concept identity of a component. For example, if two dimensions take their identity from concepts with same identity (regardless of whether the concepts exist in different schemes) one of the dimensions must be provided a different explicit identifier. Although there are XML schema constraints to help enforce this, these only apply to explicitly assigned identifiers. Identifiers inherited from a concept from which a component takes its identity cannot be validated against this constraint. Therefore, systems processing data structure definitions will have to perform this check outside of the XML validation. There are also two reserved identifiers in a data structure definition; TIME_PERIOD, and REPORTING_YEAR_START_DAY. These identifiers may not be used outside of their respective defintions (TimeDimension and ReportingYearStartDay). This applies to both the explicit identifiers that can be assigned to the components or groups as well as an identifier inherited by a component from its concept identity. For example, if an ordinary dimension (i.e. not the time dimension) takes its concept identity from a concept with the identifier TIME_PERIOD, that dimension must provide a different explicit identifier. + + + + + + + + + + DataStructureComponentsBaseType is an abstract base type the serves as the basis for the DataStructureComponentsType. This type is necessary to allow for valid substitutions of component lists. + + + + + + + + + + DataStructureComponentsType describes the structure of the grouping to the sets of metadata concepts that have a defined structural role in the data structure definition. At a minimum at least one dimension must be defined. + + + + + + + + + + + + + + + + AttributeList describes the attribute descriptor for the data structure definition. It is a collection of metadata concepts that define the attributes of the data structure definition. + + + + + + AttributeListBaseType is an abstract base type used as the basis for the AttributeListType. + + + + + + + + + + + The id attribute is provided in this case for completeness. However, its value is fixed to AttributeDescriptor. + + + + + + + + + AttributeListType describes the attribute descriptor for the data structure definition. + + + + + + + + + + + + + + Attribute describes the definition of a data attribute, which is defined as a characteristic of an object or entity. + + + + + + AttributeBaseType is an abstract base type that serves as the basis for the AttributeType. It restricts the text format base to a text format valid for data components (that does not allow for XHTML representation). The local representation is restricted to the values defined in codelist. The concept role is restricted to the values valid for a data attribute. + + + + + + + + + + + + + + + + + AttributeType describes the structure of a data attribute, which is defined as a characteristic of an object or entity. The attribute takes its semantic, and in some cases it representation, from its concept identity. An attribute can be coded by referencing a code list from its coded local representation. It can also specify its text format, which is used as the representation of the attribute if a coded representation is not defined. Neither the coded or uncoded representation are necessary, since the attribute may take these from the referenced concept. An attribute specifies its relationship with other data structure components and is given an assignment status. These two properties dictate where in a data message the attribute will be attached, and whether or not the attribute will be required to be given a value. A set of roles defined in concept scheme can be assigned to the attribute. + + + + + + + ConceptRole references concepts which define roles which this attribute serves. + + + + + AttributeRelationship describes how the value of this attribute varies with the values of other components. These relationships will be used to determine the attachment level of the attribute in the various data formats. + + + + + MeasureRelationship identifies the measures that the attribute applies to. If this is not used, the attribute is assumed to apply to all measures. + + + + + + The usage attribute indicates whether an attribute value must be available for any corresponding existing observation. + + + + + + + + + AttributeRelationshipType defines the structure for stating the relationship between an attribute and other data structure definition components. + + + + + This means that the value of the attribute varies per dataflow. It is the data modeller's responsibility to design or use non-overlapping dataflows that do not have observations in common, otherwise the integrity of dataflow-specific attribute values is not assured by the model, e.g. when querying those data through its DSD. + + + + + + This is used to reference dimensions in the data structure definition on which the value of this attribute depends. An attribute using this relationship can be either a group, series (or section), or observation level attribute. The attachment level of the attribute will be determined by the data format and which dimensions are referenced. + + + + + + This is used as a convenience to referencing all of the dimension defined by the referenced group. The attribute will also be attached to this group. + + + + + This is used to specify that the value of the attribute is dependent upon the observed value. An attribute with this relationship will always be treated as an observation level attribute. + + + + + + + + + + + + + + + + MeasureRelationshipType allows for the description of an attributes relationship to one or more measures + + + + + This is a reference to a measure defined in this data structure definition. + + + + + + + + MetadataAttributeUsage refines the details of how a metadata attribute from the metadata structure referenced from the data structure is used. By default, metadata attributes can be expressed at any level of the data. This allows an attribute relationship to be defined in order restrict the reporing of a metadata attribute to a specific part of the data. + + + + + + MetadataAttributeUsageBaseType is the abstract base refinement of a metadata attribute usage. Since this is a usage of metadata attribute already defined in metadata structure, the typical id, concept identity, and representation are excluded in place of a local refernce to the metadata attribute being used. + + + + + + + + + + + + + + + + + MetadataAttributeUsageType defines the structure of how a metadata attribute is used in a data structure. This is a local reference to a metadata attribute from the metadata structure referenced by the data structure. An attribute relationship can be defined in order to describe the relationship of the metadata attribute to the data structure components. + + + + + + + MetadataAttributeReference is a local reference to a metadata attribute defined in the metadata structure referenced by this data structure. + + + + + AttributeRelationship defines the relationship between the referenced metadata attribute and the components of the data structure. + + + + + + + + + + DimensionList describes the key descriptor for the data structure definition. It is an ordered set of metadata concepts that, combined, classify a statistical series, such as a time series, and whose values, when combined (the key) in an instance such as a data set, uniquely identify a specific series. + + + + + + DimensionListBaseType is an abstract base type used as the basis for the DimensionListType. + + + + + + + + + + + The id attribute is provided in this case for completeness. However, its value is fixed to DimensionDescriptor. + + + + + + + + + DimensionListType describes the key descriptor for a data structure definition. The order of the declaration of child dimensions is significant: it is used to describe the order in which they will appear in data formats for which key values are supplied in an ordered fashion (exclusive of the time dimension, which is not represented as a member of the ordered key). Any data structure definition which uses the time dimension should also declare a frequency dimension, conventionally the first dimension in the key (the set of ordered non-time dimensions). If is not necessary to assign a time dimension, as data can be organised in any fashion required. + + + + + + + + + + + + + + BaseDimensionBaseType is an abstract base type that serves as the basis for any dimension. It restricts the text format base to a text format valid for data components (that does not allow for XHTML representation). + + + + + + + + + + + + + + + + BaseDimensionType is an abstract base type which defines the basic structure of all dimensions. + + + + + + + ConceptRole references concepts which define roles which this dimension serves. + + + + + + The order of the dimensions in the key descriptor (DimensionList element) defines the order of the dimensions in the data structure. This position attribute explicitly specifies the position of the dimension in the data structure. It is optional and if specified must be consistent with the position of the dimension in the key descriptor. + + + + + + + + + Dimension describes the structure of a dimension, which is defined as a statistical concept used (most probably together with other statistical concepts) to identify a statistical series, such as a time series, e.g. a statistical concept indicating certain economic activity or a geographical reference area. + + + + + + DimensionType describes the structure of an ordinary dimension, which is defined as a statistical concept used (most probably together with other statistical concepts) to identify a statistical series, such as a time series, e.g. a statistical concept indicating certain economic activity or a geographical reference area. The dimension takes its semantic, and in some cases it representation, from its concept identity. A dimension can be coded by referencing a code list from its coded local representation. It can also specify its text format, which is used as the representation of the dimension if a coded representation is not defined. Neither the coded or uncoded representation are necessary, since the dimension may take these from the referenced concept. + + + + + + + + + + + + + + + + + + TimeDimension is a special dimension which designates the period in time in which the data identified by the full series key applies. + + + + + + TimeDimensionType describes the structure of a time dimension. The time dimension takes its semantic from its concept identity (usually the TIME_PERIOD concept), yet is always has a fixed identifier (TIME_PERIOD). The time dimension always has a fixed text format, which specifies that its format is always the in the value set of the observational time period (see common:ObservationalTimePeriodType). It is possible that the format may be a sub-set of the observational time period value set. For example, it is possible to state that the representation might always be a calendar year. See the enumerations of the textType attribute in the LocalRepresentation/TextFormat for more details of the possible sub-sets. It is also possible to facet this representation with start and end dates. The purpose of such facts is to restrict the value of the time dimension to occur within the specified range. If the time dimension is expected to allow for the standard reporting periods (see common:ReportingTimePeriodType) to be used, then it is strongly recommended that the reporting year start day attribute also be included in the data structure definition. When the reporting year start day attribute is used, any standard reporting period values will be assumed to be based on the start day contained in this attribute. If the reporting year start day attribute is not included and standard reporting periods are used, these values will be assumed to be based on a reporting year which begins January 1. + + + + + + + + + + + + + + + + + + + Group describes a group descriptor in a data structure definition. It is a set metadata concepts (and possibly their values) that define a partial key derived from the key descriptor in a data structure definition. + + + + + + GroupBaseType is an abstract base type that forms the basis for the GroupType. + + + + + + + + + + + + + + + GroupType describes the structure of a group descriptor in a data structure definition. A group may consist of a of partial key, or collection of distinct cube regions or key sets to which attributes may be attached. The purpose of a group is to specify attributes values which have the same value based on some common dimensionality. All groups declared in the data structure must be unique - that is, you may not have duplicate partial keys. All groups must be given unique identifiers. + + + + + + + + + + + + + GroupDimension is a component which contains only a reference to a dimension in the key descriptor (DimensionList). Although it is conventional to declare dimensions in the same order as they are declared in the ordered key, there is no requirement to do so - the ordering of the values of the key are taken from the order in which the dimensions are declared. Note that the id of a dimension may be inherited from its underlying concept - therefore this reference value may actually be the id of the concept. + + + + + + GroupDimensionBaseType is an abstract base type which refines the base ComponentType in order to form the basis for the GroupDimensionType. + + + + + + + + + + + + + GroupDimensionType defines a dimension component with a group key descriptor component list. Although technically a component, this is essentially a reference to a dimension defined in the key descriptor. Therefore, the identification, name, and description, concept identity and representation properties that are typically available for a component are not allowed here, as they are all inherited from the referenced dimension. + + + + + + + DimensionReference provides a reference to a dimension defined in the key descriptor of the data structure definition in which this group key descriptor is defined. + + + + + + + + + + MeasureList describes the measure descriptor for a data structure. + + + + + + MeasureListType describes the structure of the measure descriptor for a data structure definition. + + + + + + + + + + + + + + + + + + + Measure defines the structure of a measure, which is the concept that is the value of the phenomenon to be measured in a data set. + + + + + + MeasureBaseType is an abstract base type that refines ComponentType to rerstrict the represenations to those which are applicable for a measure. + + + + + + + + + + + + + + + + + MeasureType defines the structure of a measure descriptor. In addition to the identifying concept and representation, a usage status and max occurs can be defined. + + + + + + + ConceptRole references concepts which define roles which this measure serves. + + + + + + The usage attribute indicates whether a measure value must be available for any corresponding existing observation. + + + + + + + + + DataStructureRepresentationType is an abstract base type which defines the allowable representations for any data structure definition component. The enumeration must be restricted to the proper type for item scheme for a given component. + + + + + + + + + + + + + + + + + + AttributeRepresentationType defines the representation for a data attribute. A data attribute can be text (including XHTML and multi-lingual values), a simple value, or an enumerated value. + + + + + + + + + + + + + + + + + + MeasureRepresentationType defines the representation for a measure. A measure can be text (including XHTML and multi-lingual values), a simple value, or an enumerated value. + + + + + + + + + + + + + + + + + + SimpleDataStructureRepresentationType defines the representation for any non-time dimension data structure definition component. + + + + + + + + + + + + + + + + + + TimeDimensionRepresentationType defines the representation for the time dimension. Enumerated values are not allowed. + + + + + + + + + + + + + An enumeration of optional | mandatory to indicate the usage of an attribute or measure. + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureDataflow.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureDataflow.xsd new file mode 100644 index 0000000..41c7bb4 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureDataflow.xsd @@ -0,0 +1,34 @@ + + + + + + + + SDMX Dataflow Structure Module + The data flow structure module defines the structure of data flow constructs. + + + + + DataflowType describes the structure of a data flow. A data flow is defined as the structure of data that will provided for different reference periods. If this type is not referenced externally, then a reference to a data structure must be provided. + + + + + + + + + + + Structure provides a reference to the data structure definition which defines the structure of all data for this flow. + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureHierarchicalCodelist.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureHierarchicalCodelist.xsd new file mode 100644 index 0000000..cf2c843 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureHierarchicalCodelist.xsd @@ -0,0 +1,237 @@ + + + + + + + + SDMX Hierarchical Code List Structure Module + The hierarchical code list structure module defines the structure of hierarchical code list constructs. + + + + + HierarchyBaseType is an abstract base class that is the basis for the HierarchyType. It requires that a name be supplied. + + + + + + + + + + + + + + + + + HierarchyType describes the structure of a hierarchical codelist. A hierarchical code list is defined as an organised collection of codes that may participate in many parent/child relationships with other codes in the list. + + + + + + + In a formally leveled hierarchy, Level describes a group of codes which are characterised by homogeneous coding, and where the parent of each code in the group is at the same higher level of the hierarchy. In a value based hierarchy Level describes information about the codes at the specified nesting level. This structure is recursive to indicate the hierarchy of the levels. + + + + + HierarchicalCode is used to assemble the codes from the codelist(s) referenced into a hierarchy. + + + + + + + + + + If “true”, this indicates a hierarchy where the structure is arranged in levels of detail from the broadest to the most detailed level. If “false”, this indicates a hierarchy structure where the items in the hierarchy have no formal level structure. + + + + + + + + + HierarchicalCodeBaseType is an abstract base type the creates the basis for the HierarchicalCodeType. It removes the urn and uri. + + + + + + + + + + + The id attribute allows for an id to be assigned to the use of the particular code at that specific point in the hierarchy. This value is unique within the hierarchy being created, and is used to map the hierarchy against external structures. + + + + + + + + + HierarchicalCodeType describes the structure of a hierarchical code. A hierarchical code provides for a reference to a code that is referenced within the hierarchical code list via either a complete reference to a code through either a URN or full set of reference fields. Codes are arranged in a hierarchy by this reference. Note that it is possible to reference a single code such that it has multiple parents within the hierarchy. Further, the hierarchy may or may not be a leveled one. + + + + + + + Code provides a complete, explicit reference to a code through either its URN, or a complete reference to the codelist and code. + + + + + HierarchicalCode is used to nest referenced codes into a value based hierarchy. + + + + + + + + + Level references a formal level defined within the hierarchy which defines this hierarchical code. This is only necessary if the nesting depth of the hierarchical code does not correspond to the nesting depth of the level to which it belongs (i.e. the hieararchical code is to skip down a level). Otherwise, the code is assumed to exist at the level in which the nesting depth of the level matches the nesting depth of the code. + + + + + + The validFrom attriubte indicates the point in time in which the hiearchical code became effective. This can be used to track the historicity of codes changing over time. + + + + + The validTo attriubte indicates the point in time in which the hiearchical code became no longer effective. This can be used to track the historicity of codes changing over time. + + + + + + + + + LevelBaseType is an abstract base type that makes up the basis for the LevelType. It requires a name and id. + + + + + + + + + + + + + + + + + + LevelType describes a level in a hierarchical codelist. Where level is defined as a group where codes can be characterised by homogeneous coding, and where the parent of each code in the group is at the same higher level of the hierarchy. + + + + + + + CodingFormat specifies the text formatting of the codes in this level. This includes facets such as the expected characters and the length of the codes. + + + + + Level describes the next level down in the hierarchy. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HierarchyAssociationBaseType defines the base refinement of the HierarchyAssociationType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + HierarchyAssociationType defines the structure of a hiearchy association, which links a hierarchy with and identifiable object in the context of another object (e.g. a dimension within the context of a dataflow). + + + + + + + The associated hierarchy. + + + + + Associates the Identifiable Artefact that needs the Hierarchy. + + + + + The context within which the association is performed. + + + + + + + + + + SimpleCodeDataType restricts SimpleDataType to specify the allowable data types for a simple code. The possible values are simply Alpha, AlphaNumeric, or Numeric. + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataStructure.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataStructure.xsd new file mode 100644 index 0000000..c263bd9 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataStructure.xsd @@ -0,0 +1,166 @@ + + + + + + + + SDMX Metadata Structure Structure Module + The Metadata Structure structure module defines the structure of metadata structure definition constructs. + + + + + MetadataStructureType is used to describe a metadata structure definition, which is defined as a collection of metadata concepts, their structure and usage when used to collect or disseminate reference metadata. + + + + + + + + + + + + + + + + + + + + MetadataStructureComponents defines the grouping of the sets of the components that make up the metadata structure definition. + + + + + + MetadataStructureComponentsBaseType is an abstract base type that forms the basis for the MetadataStructureComponentsType. + + + + + + + + + MetadataStructureComponentsType describes the structure of the grouping of the sets of the components that make up the metadata structure definition. + + + + + + + + + + + + + MetadataAttributeList defines the set of metadata attributes that can be defined as a hierarchy, for reporting reference metadata about a target object. The identification of metadata attributes must be unique at any given level of the metadata structure. Although there are XML schema constraints to help enforce this, these only apply to explicitly assigned identifiers. Identifiers inherited from a concept from which a metadata attribute takes its identity cannot be validated against this constraint. Therefore, systems processing metadata structure definitions will have to perform this check outside of the XML validation. + + + + + + + + + + MetadataAttributeListType describes the structure of a meta data attribute list. It comprises a set of metadata attributes that can be defined as a hierarchy. + + + + + + + + + + + + + The id attribute is provided in this case for completeness. However, its value is fixed to MetadataAttributeDescriptor. + + + + + + + + + MetadataAttribute defines the a metadata attribute, which is the value of an attribute, such as the instance of a coded or uncoded attribute in a metadata structure definition. + + + + + + + + + + MetadataAttributeBaseType is an abstract base type the serves as the basis for the MetadataAttributeType. + + + + + + + + + + + + + + + + + MetadataAttributeType describes the structure of a metadata attribute. The metadata attribute takes its semantic, and in some cases it representation, from its concept identity. A metadata attribute may be coded (via the local representation), uncoded (via the text format), or take no value. In addition to this value, the metadata attribute may also specify subordinate metadata attributes. If a metadata attribute only serves the purpose of containing subordinate metadata attributes, then the isPresentational attribute should be used. Otherwise, it is assumed to also take a value. If the metadata attribute does take a value, and a representation is not defined, it will be inherited from the concept it takes its semantic from. The optional id on the metadata attribute uniquely identifies it within the metadata structured definition. If this id is not supplied, its value is assumed to be that of the concept referenced from the concept identity. Note that a metadata attribute (as identified by the id attribute) definition must be unique across the entire metadata structure definition. + + + + + + + + + The minOccurs attribute indicates the minimum number of times this metadata attribute must occur within its parent object. + + + + + The maxOccurs attribute indicates the maximum number of times this metadata attribute can occur within its parent object. + + + + + The isPresentational attribute indicates whether the metadata attribute should allow for a value. A value of true, meaning the metadata attribute is presentational means that the attribute only contains child metadata attributes, and does not contain a value. If this attribute is not set to true, and a representation (coded or uncoded) is not defined, then the representation of the metadata attribute will be inherited from the concept from which it takes its identity. + + + + + + + + + MetadataAttributeRepresentationType defines the possible local representations of a metadata attribute. + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataflow.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataflow.xsd new file mode 100644 index 0000000..d382ddd --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureMetadataflow.xsd @@ -0,0 +1,51 @@ + + + + + + + + SDMX Metadataflow Structure Module + The metadata flow structure module defines the structure of metadata flow constructs. + + + + + MetadataflowBaseType is an abstract base type that serves as the basis for the MetadataflowType. It restricts the structure to reference a metadata structure definition. + + + + + + + + + + + Structure provides a reference to the metadata structure definition describing the structure of all reference metadata for this flow. + + + + + + + + + + + MetadataflowType describes the structure of a metadata flow. A dataflow is defined as the structure of reference metadata that will be provided for different reference periods. If this type is not referenced externally, then a reference to a metadata structure definition must be provided + + + + + + + References identifiable structures to which the refernece metadata described by the referenced metadata structure should be restricted to. These references may include wildcards for parts of the reference. + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureOrganisation.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureOrganisation.xsd new file mode 100644 index 0000000..4103245 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureOrganisation.xsd @@ -0,0 +1,371 @@ + + + + + + + + SDMX Organisation Structure Module + The organisation structure module defines the structure of organisation schemes and organisation constructs. + + + + + OrganisationSchemeBaseType is an abstract base type for any organisation scheme. + + + + + + + + + + + + + + + + + OrganisationSchemeType describes the structure of an organisation scheme. + + + + + + + + + + + + + Organisation is an abstract substitution head for a generic organisation. + + + + + + BaseOrganisationType is an abstract base type the forms the basis for the OrganisationType. + + + + + + + + + + + + If the particular organisation scheme allows, an organisation may reference a parent organisation defined in the same scheme. This does not affect the identification of the organisation, but rather only serves to state the relationship. + + + + + + + + + + + OrganisationType in an abstract type which describes the structure of the details of an organisation. In addition to the basic organisation identification, contact details can be provided. + + + + + + + Contact describes a contact for the organisation, + + + + + + + + + + AgencySchemeType defines a specific type of organisation scheme which contains only maintenance agencies. The agency scheme maintained by a particular maintenance agency is always provided a fixed identifier and is never versioned. Therefore, agencies can be added or removed without have to version the scheme. Agencies schemes have no hierarchy, meaning that no agency may define a relationship with another agency in the scheme. In fact, the actual parent agency for an agency in a scheme is the agency which defines the scheme. + + + + + + + + + + + + + + + + + + + + + DataConsumerSchemeType defines a type of organisation scheme which contains only data consumers. The data consumer scheme maintained by a particular maintenance agency is always provided a fixed identifier and is never versioned. Therefore, consumers can be added or removed without have to version the scheme. This scheme has no hierarchy, meaning that no organisation may define a relationship with another organisation in the scheme. + + + + + + + + + + + + + + + + + + + + + DataProviderSchemeType defines a type of organisation scheme which contains only data providers. The data provider scheme maintained by a particular maintenance agency is always provided a fixed identifier and is never versioned. Therefore, providers can be added or removed without have to version the scheme. This scheme has no hierarchy, meaning that no organisation may define a relationship with another organisation in the scheme + + + + + + + + + + + + + + + + + + + + + MetadataProviderSchemeType defines a type of organisation scheme which contains only metadata providers. The metadata provider scheme maintained by a particular maintenance agency is always provided a fixed identifier and is never versioned. Therefore, providers can be added or removed without have to version the scheme. This scheme has no hierarchy, meaning that no organisation may define a relationship with another organisation in the scheme + + + + + + + + + + + + + + + + + + + + + OrganisationUnitSchemeType defines a type of organisation scheme which simply defines organisations and there parent child relationships. Organisations in this scheme are assigned no particular role, and may in fact exist within the other type of organisation schemes as well. + + + + + + + + + + + + + + + + + + + + Agency is an organisation which maintains structural metadata such as classifications, concepts, data structures, and metadata structures. + + + + + + DataConsumer describes an organisation using data as input for further processing. + + + + + + DataProvider describes an organisation that produces data. + + + + + + MetadataProvider describes an organisation that produces metadata . + + + + + + OrganisationUnit describes a generic organisation, which serves not predefined role in SDMX. + + + + + + AgencyType defines the structure of an agency description. The contacts defined for the organisation are specific to the agency role the organisation is serving. + + + + + + + + + + + + + + The id attribute holds the identification of the agency. The type of this id is restricted to the common:NCNNameIDType. This is necessary, since the agency identifier will be used as part of the name for simple types in data and metadata structure specific schemas and therefore must be compliant with the NCName type in XML Schema (see common:NCNameIDType for further details). + + + + + + + + + DataConsumerType defines the structure of a data consumer description. The contacts defined for the organisation are specific to the data consumer role the organisation is serving. + + + + + + + + + + + + + + + + + + DataProviderType defines the structure of a data provider description. The contacts defined for the organisation are specific to the data provider role the organisation is serving. + + + + + + + + + + + + + + + + + + MetadataProviderType defines the structure of a metadata provider description. The contacts defined for the organisation are specific to the metadata provider role the organisation is serving. + + + + + + + + + + + + + + + + + + OrganisationUnitType defines the structure of an organisation unit description. In addition to general identification and contact information, an organisation unit can specify a relationship with another organisation unit from the same scheme which is its parent organisation. + + + + + + + + + + + + + + + + + + + + + ContactType describes the structure of a contact's details. + + + + + + Department is designation of the organisational structure by a linguistic expression, within which the contact person works. + + + + + Role is the responsibility of the contact person with respect to the object for which this person is the contact. + + + + + + Telephone holds the telephone number for the contact person. + + + + + Fax holds the fax number for the contact person. + + + + + X400 holds the X.400 address for the contact person. + + + + + URI holds an information URL for the contact person. + + + + + Email holds the email address for the contact person. + + + + + + + The id attribute is used to carry user id information for the contact. + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureProcess.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureProcess.xsd new file mode 100644 index 0000000..a53f414 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureProcess.xsd @@ -0,0 +1,210 @@ + + + + + + + + SDMX Process Structure Module + The process structure module defines the structure of process and process step constructs. + + + + + ProcessBaseType defines the base refinement of the ProcessType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + ProcessType describes the structure of a process, which is a scheme which defines or documents the operations performed on data in order to validate data or to derive new information according to a given set of rules. Processes occur in order, and will continue in order unless a transition dictates another step should occur. + + + + + + + ProcessStep defines a process step, which is a specific operation, performed on data in order to validate or to derive new information according to a given set of rules. + + + + + + + + + + + + + + ProcessStepBaseType is an abstract base type used as the basis for the ProcessStepType. + + + + + + + + + + + + + + + + + + ProcessStepType describes the structure of a process step. A nested process step is automatically sub-ordinate, and followed as the next step. If the following step is conditional, it should be referenced in a transition. + + + + + + + Input references an object which is an input to the process step. + + + + + Output references an object which is an output form the process step. + + + + + Computation describes the computations involved in the process, in any form desired by the user (these are informational rather than machine-actionable), and so may be supplied in multiple, parallel-language versions. + + + + + Transition describes the next process steps. Each transition in a process step should be evaluated, allowing for multiple process step branches from a single process step. + + + + + ProcessStep defines a process step, which is a specific operation, performed on data in order to validate or to derive new information according to a given set of rules. + + + + + + + + + + + + + + TransitionBaseType defines the base refinement of the TransitionType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + TransitionType describes the details of a transition, which is an expression in a textual or formalised way of the transformation of data between two specific operations performed on the data. + + + + + + + TargetStep references a process step within the process that should be transitioned to, should the conditions described be met. + + + + + Condition is a textual description of the conditions to be met in order for the target step to be proceeded to. It is informational only (not machine-actionable), and may be supplied in multiple, parallel-language form. + + + + + + The localID attribute is an optional identification for the transition within the process. + + + + + + + + + ComputationType describes a computation in a process. + + + + + + + Description describe the computation in any form desired by the user (these are informational rather than machine-actionable), and so may be supplied in multiple, parallel-language versions, + + + + + + The localID attribute is an optional identification for the computation within the process. + + + + + The softwarePackage attribute holds the name of the software package that is used to perform the computation. + + + + + The softwareLanguage attribute holds the coding language that the software package used to perform the computation is written in. + + + + + The softwareVersion attribute hold the version of the software package that is used to perform that computation. + + + + + + + + + InputOutputType describes the structure of an input or output to a process step. It provides a reference to the object that is the input or output. + + + + + + + ObjectReference is an abstract substitution head that references the object that is an input or output. It is substituted with a concrete reference to an explicit object type. + + + + + + The localID attribute is an optional identification for the input or output within the process. + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureProvisionAgreement.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureProvisionAgreement.xsd new file mode 100644 index 0000000..3a011b8 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureProvisionAgreement.xsd @@ -0,0 +1,95 @@ + + + + + + + + SDMX Provision Agreement Module + The provision agreement module defines the structure of the provision agreement constructs. + + + + + ProvisionAgreementBaseType defines the base refinement of the ProvisionAgreementType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + ProvisionAgreementType describes the structure of a provision agreement. A provision agreement defines an agreement for a data provider to report data against a dataflow. Attributes which describe how the registry must behave when data or metadata is registered against this provision agreement are supplied. + + + + + + + Dataflow provides a reference to a pre-existing dataflow in the registry. The reference is provided via a URN and/or a full set of reference fields. + + + + + DataProvider provides a reference to a pre-existing data provider in the registry. The reference is provided via a URN and/or a full set of reference fields. + + + + + + + + + + MetadataProvisionAgreementBaseType defines the base refinement of the MetadataProvisionAgreementType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + ProvisionAgreementType describes the structure of a provision agreement. A provision agreement defines an agreement for a data provider to report data or reference metadata against a flow. Attributes which describe how the registry must behave when data or metadata is registered against this provision agreement are supplied. + + + + + + + Metadataflow provides a reference to a pre-existing metadataflow in the registry. The reference is provided via a URN and/or a full set of reference fields. + + + + + MetadataProvider provides a reference to a pre-existing metadata provider in the registry. The reference is provided via a URN and/or a full set of reference fields. + + + + + References identifiable structures to which the refernece metadata described by the metadata structure used by the metadaflow should be restricted to. These references may include wildcards for parts of the reference. + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureReportingTaxonomy.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureReportingTaxonomy.xsd new file mode 100644 index 0000000..eb7727e --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureReportingTaxonomy.xsd @@ -0,0 +1,86 @@ + + + + + + + + SDMX Reporting Taxonomy Structure Module + The reporting taxonomy structure module defines the structure of reporting taxonomy and reporting category constructs. + + + + + ReportingTaxonomyType describes the structure of a reporting taxonomy, which is a scheme which defines the composition structure of a data report where each component can be described by an independent structure or structure usage description. + + + + + + + + + + + + + + + + + + + + ReportingCateogry defines a reporting category, which is used to group structure usages into useful sub-packages. + + + + + + + + + + ReportingCategoryBaseType is an abstract base type that serves as the basis for the ReportingCategoryType. + + + + + + + + + + + + + + + + + + + + + + ReportingCategoryType describes the structure of a reporting category, which groups structure usages into useful sub-packages. Sub ordinate reporting categories can be nested within the category definition. + + + + + + + StructuralMetadata provides a reference for data structure definition and metadata structure definition references which are grouped in the reporting category. It is assumed that all structural metadata objects referenced from a category will be of the same type. + + + + + ProvisioningMetadata provides a reference for dataflow and metadataflow references which are grouped in the reporting category. It is assumed that all provisioning metadata objects referenced from a category will be of the same type. + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureStructureMappings.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureStructureMappings.xsd new file mode 100644 index 0000000..f91eed2 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureStructureMappings.xsd @@ -0,0 +1,478 @@ + + + + + + + + SDMX Structure Mapping Structure Module + The structure Mapping structure module defines the structure of structure mapping constructs. + + + + + ItemSchemeMapBaseType is an abstract base type which forms the basis for the ItemSchemeMapType. + + + + + + + + + + + + + + + + + ItemSchemeMapType is an abstract base type which forms the basis for mapping items between item schemes of the same type. + + + + + + + Source provides a reference to the item scheme which items are mapped from. + + + + + Target provides a reference to the item scheme which items are mapped to. + + + + + + + + + + + OrganisationSchemeMapType defines the structure of a map which identifies relationships between organisations in different organisation schemes. + + + + + + + + + + + + + + + + + + + + CategorySchemeMapType defines the structure of a map which identifies relationships between categories in different category schemes. + + + + + + + + + + + + + + + + + + + + ConceptSchemeMapType defines the structure of a map which identifies relationships between concepts in different concept schemes. + + + + + + + + + + + + + + + + + + + + ReportingTaxonomyMapType defines the structure of a map which identifies relationships between reporting categories in different reporting taxonomies. + + + + + + + + + + + + + + + + + + + + StructureMapBaseType defines the base refinement of the StructureMapType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + StructureMapType defines the structure for mapping components of one structure to components of another structure. A structure may be referenced directly meaning the map applies wherever the structure is used, or it may be a reference via a structure usage meaning the map only applies within the context of that usage. Using the related structures, one can make extrapolations between maps. For example, if key families, A, B, and C, are all grouped in a related structures container, then a map from data structure A to C and a map from data structure B to C could be used to infer a relation between data structure A to C. + + + + + + + Source provides a reference to a structure (data or metadata) or a structure usage (dataflow or metadataflow) from which components defined by the actual structure are to mapped. + + + + + Target provides a reference to a structure (data or metadata) or a structure usage (dataflow or metadataflow) to which components from the source are to mapped. + + + + + Provides the ability to map source to target date formats. The source date is described as the number of epochs since a point in time, where the duration of each epoch is defined, e.g. number of milliseconds since 1970. + + + + + Provides the ability to map source to target date formats. The source date is described as a pattern (for example MM-YYYY). + + + + + + + + + + ComponentMap defines the relationship between the components of the source and target structures, including information on how the value from the source component relates to values in the target component. + + + + + FixedValueMap defines a fixed value for a source or target component in the mapping. + + + + + + + + + + FixedValueMapType defines the structure for providing a fixed value for a source or target component. + + + + + + + + + + + The fixed value for the component. + + + + + + + + + + ComponentMapType defines the structure for relating a component in a source structure to a component in a target structure. + + + + + + + + + + + + + + + FrequencyFormatMappingBaseType defines the base refinement of the FrequencyFormatMappingType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Indicates the point in time to resolve to when mapping from low fequency periods to higher frequency periods. + + + + + + + + + EpochMapBaseType defines the base refinement of the EpochMapType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DatePatternMapBaseType defines the base refinement of the DatePatternMapType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Describes the source date using conventions for describing years, months, days, etc. + + + + + The locale on which the input will be parsed according to the pattern. + + + + + + + + + RepresentationMapBaseType defines the base refinement of the RepresentationMapType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SingleValueMappingType defines a mapping with a single source and optional target. + + + + + + + There should be a source value for each source represention (e.g. codelist, data type). Source values can be pattern matched by using regular expression or substrings using start/end indexes. + + + + + The target value(s) is always an absolute string. However, if source value is a regular expression, the target value can output the capture group from the source. + + + + + + + + + + + + ValueMappingType defines a mapping of multiple sources to multiple targets. + + + + + + + There should be a source value for each source represention (e.g. codelist, data type). Source values can be pattern matched by using regular expression or substrings using start/end indexes. + + + + + The target value(s) is always an absolute string. However, if source value is a regular expression, the target value can output the capture group from the source. + + + + + + + + + + + + + + + + + + + + + + EpochPeriodType defines an enumeration of epoch period types. + + + + + + + + + + + + + ResolvePeriodType defines an enumeration of how date periods should be resolved. + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureTransformation.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureTransformation.xsd new file mode 100644 index 0000000..b33130a --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/SDMXStructureTransformation.xsd @@ -0,0 +1,670 @@ + + + + + + + + SDMX Transformation Structure Module + The transformation structure module defines the structure of transformation scheme and transformation constructs. + + + + + VtlDefinitionSchemeType is an abstract extension of the ItemSchemeType for VTL schemes. + + + + + + Identifies the VTL version to which the items in the defined scheme comply. Note that definition schemes can only reference definition schemes using the same VTL version. + + + + + + + + + TransformationSchemeBaseType is an abstract base type for the TransformationSchemeType. It restricts the item types to be only transformations. + + + + + + + + + + + + + + + + + + + + TransformationSchemeType describes the structure of a transformation scheme. A transformation scheme contains a set of transformations to be executed together (in the same run). It can contain any number of transformations that produce any number of results. + + + + + + + References a VTL mapping scheme which defines aliases for given SDMX artefacts that are used in the transformations as well as the mapping methods used when converting between SDMX and VTL data structures. All aliases must be defined in the referenced scheme. This also must be used if the basic mapping methods are not used. + + + + + References a name personalisation scheme, which defines the overriding of some standard VTL names (to be assigned to some measures and/or attributes of the data structure) with some corresponding personalised names. This must be used if transformations within a transformation scheme personalise standard names. All personalisations must be defined in the referenced scheme. + + + + + References a custom type scheme which defines custom conversions of VTL scalar types to SDMX data types. This must be used if custom type conversions are used in the transformations defined in a transformation scheme. All custom conversions must be defined in the referenced scheme. + + + + + References a ruleset scheme that defines one or more previously defined rulesets which can be invoked by VTL operators. If a transformation defined in a transformation scheme refers to a ruleset, the scheme in which the ruleset is defined must be referenced here. + + + + + References a user defined operator scheme that defines one or more user defined operators used by the transformations defined in a transformation scheme. If a transformation in a transformation scheme refers to a user defined operator, the scheme in which the user defined operator is defined must be referenced here. + + + + + + + + + + Transformation describes the details of a single transformation within a transformation scheme. + + + + + + TransformationBaseType defines the base refinement of the TransformationType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + TransformationType defines the structure of a transformation. A transformation is an assignment of a VTL expression to a specific result. + + + + + + + The right-hand side of the VTL statement. This is expression that is executed for this transformation. It include references to operands and other artefacts. The expression may contain references to SDMX artefacts using the reduced URN format; see Section 6 SDMX Standards ("SDMX Technical Notes"), 10.2.3 ("Abbreviation of the URN"). + + + + + The left-hand side of the VTL statement. This identifies the result artefact, which may be used in subsequent transformations. If the result is an SDMX artefact, the is expressed using the alias; see Section 6 SDMX Standards ("SDMX Technical Notes"), 10.2.3 ("Abbreviation of the URN"). + + + + + + Indicates if the the result is permanently stored. A persistent result (value of true) can be used by transformation defined in other transformation schemes, but a non-persistent result (value of false) can only be used by transformations within the same transformation scheme. + + + + + + + + + VtlMappingSchemeType defines a set of mappings between SDMX and VTL. + + + + + + + + + + + + + + + + + + + + VtlMapping details a mapping between SDMX and VTL transformation. + + + + + + VtlMappingBaseType defines the base refinement of the VtlMappingType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + VtlMappingType defines the structure of a single mapping between the reference to a SDMX artefact made from VTL transformations, rulesets, user defined operators and the corresponding SDMX structure identifier. These are used to assign an alternative names to SDMX Dataflows, Codelists, Concept Schemes, or Concepts. Although are distinct sub-classes in the Information Model, this structure serves to express them all. The references SDMX artefact serves to distinguish which type of sub-class (VtlDatflowMapping or VtlCodelistMapping, or VtlConceptMapping) is being described. When this is used to assign an alias for a SDMX Dataflow, this can also be used to indicate the methods used to convert the data structure from SDMX to VTL and vice-versa. Finally, this can be used to override the deault Basic mapping methods used for Dataflows by utilizing the GenericDataflow element in place of a reference to a specific Dataflow. + + + + + + + + + + A reference to the SDMX Dataflow that the mapping is defined for. This is used to create a VtlDataflowMapping. In this case, it is possible to specify the mapping details to and from VTL. + + + + + Indicates that the ToVtlMapping and FromVtlMapping are the default mapping methods to be applied, overriding the Basic methods if necessary. The mapping methods in this case would be applied to any dataflows that are not explicitly defined in other VtlMappings. + + + + + + Describes the mapping from a SDMX dataflow to a VTL data structure. + + + + + Describes the mapping to a SDMX dataflow from a VTL data structure. + + + + + + A reference to the SDMX Codelist that the mapping is defined for. This is used to create a VtlCodelistMapping. + + + + + A reference to the SDMX Concept that the mapping is defined for. This is used to create a VtlConceptMapping. + + + + + + + The alias used to refer to the reference SDMX artefact in the transformations. This must be unique within the mapping scheme in which it is defined. + + + + + + + + + ToVtlMappingType defines the mapping method and filter used when mapping from SDMX to VTL. + + + + + Identfies a sub space of the mapped dataflow that the mapping applies to. This is a collection of references to the dimensions that make up the space. + + + + + + The mapping method used when mapping from SDMX to VTL. This is typically a StandardToVtlMappingMethodType, but can be any other value to allow for non-standard methods. The implied default is Basic. + + + + + + + A simple type enumerating the standard mapping methods when converting from data structures from SDMX to VLT. + + + + + The default mapping method. See Section 6 SDMX Standards ("SDMX Technical Notes"), 10.3.3.1 ("Basic Mapping"). + + + + + Method for mapping multi-measure data. See Section 6 SDMX Standards ("SDMX Technical Notes"), 10.3.3.2 ("Pivot Mapping"). + + + + + The basic mapping method, using attributes to measures. See Section 6 SDMX Standards ("SDMX Technical Notes"), 10.3.3.3 ("From SDMX DataAttributes to VTL Measures"). + + + + + The pivot mapping method, using attributes to measures. See Section 6 SDMX Standards ("SDMX Technical Notes"), 10.3.3.3 ("From SDMX DataAttributes to VTL Measures"). + + + + + + + + A simple type that allows for a standard to VTL mapping method enumeration value or a string value for other mapping methods. + + + + + + + FromVtlMappingType defines the mapping method and filter used when mapping from VTL to SDMX. + + + + + Identfies a super space of the mapped dataflow that the mapping applies to. This is a collection of references to the dimensions that make up the space. + + + + + + The mapping method used when mapping from VTL to SDMX. This is typically a StandardFromVtlMappingMethodType, but can be any other value to allow for non-standard methods. The implied default is Basic for single-measure VTL data structures and Unpivot for multi-meausre VTL data structures. + + + + + + + A simple type enumerating the standard mapping methods when converting from data structures from VTL to SDMX. + + + + + The default mapping method, applicable only when the VLT data structure has just one measure component. See Section 6 SDMX Standards ("SDMX Technical Notes"), 10.3.4.1 ("Basic Mapping"). + + + + + The mapping method to be used when the VTL data structure has more than one measure component. See Section 6 SDMX Standards ("SDMX Technical Notes"), 10.3.4.2 ("Unpivot Mapping"). + + + + + Mapping of multi-measure VTL where on measure is mapped to the SDMX primary measure and the remaining measures are mapped as data attributes. See Section 6 SDMX Standards ("SDMX Technical Notes"), 10.3.4.3 ("From VTL Measures to SDMX DataAttributes"). + + + + + + + + A simple type that allows for standard from VTL mapping method enumeration value or a string value for other mapping methods. + + + + + + + SpaceKey defines the structure of a super- or sub- space for a SDMX Dataflow. It is a collection of references to the dimensions that make up the space. + + + + + A reference to a dimension by its identifier. + + + + + + + + NamePersonalisationSchemeType defines a set of personalisations of VTL standard names that are used in a set of transformations. + + + + + + + + + + + + + + + + + + + + NamePersonalisation details a name personalisation that is used in a transformation. + + + + + + NamePersonalisationBaseType defines the base refinement of the NamePersonalisationType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + NamePersonalisationType defines the structure of a name personalisation. A name personalisation is is used in place of a standard VTL name in some VTL operations. + + + + + + + Provides the VTL standard name that is being personalised. + + + + + Provides the personalised name that is used in place of the VTL standard name in the transformation expressions. + + + + + + Identifies the type of VTL model artefact that is being personalised. In VTL 2.0, this is valuedomain or variable. + + + + + + + + + RulesetSchemeBaseType is an abstract base type for the RulesetSchemeType. It restricts the item types to be only rulesets. + + + + + + + + + + + + + + + + + + + + RulesetSchemeType defines a collection of rulesets that are used in transformations. + + + + + + + References a VTL mapping scheme which defines aliases for given SDMX artefacts that are used in the rulesets. Rulesets defined on value domains reference Codelists or Concept Schemes (the latter in VTL are considered as the Value Domains of the variables corresponding to the SDMX Measure Dimensions). The rulesets defined on variables reference Concepts (for which a definite representation is assumed). Therefore, a ruleset should only refer to Codelists, Concept Schemes, and Concepts. + + + + + + + + + + Ruleset details a ruleset within a ruleset scheme. + + + + + + RulesetBaseType defines the base refinement of the RulesetType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + RulesetType defines the structure of a ruleset. A ruleset is a persistent set of rules which can be invoked by using appropriate VTL operators. + + + + + + + A VTL statement for the definition of a ruleset. This must conform to the syntax of the VTL definition language. + + + + + + The VTL type of the ruleset. In VTL 2.0, this is datapoint or hierarchical + + + + + This model artefact on which the ruleset is defined. In VTL 2.0, this is value domain or variable. + + + + + + + + + UserDefinedOperatorSchemeBaseType is an abstract base type for the UserDefinedOperatorSchemeType. It restricts the item types to be only user defined operators. + + + + + + + + + + + + + + + + + + + + UserDefinedOperatorSchemeType defines a collection of user defined operators that are used in transformations. + + + + + + + References a VTL mapping scheme which defines aliases for given SDMX artefacts that are used in the user defined operators. Although the VTL user defined operators are conceived to be defined on generic operands, so that the specific artefacts to be manipulated are passed as parameters at the invocation, it is also possible that they reference specific SDMX artefacts like Dataflows, Codelists and ConceptSchemes. In this case, the mapping schemes referenced here define the mappings to those artefacts. + + + + + References a ruleset scheme defining rulesets utilized in the user defined operators. + + + + + + + + + + UserDefinedOperator details a user defined operators within a user defined operator scheme. + + + + + + UserDefinedOperatorBaseType defines the base refinement of the UserDefinedOperatorType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + UserDefinedOperatorType defines the structure of a user defined operator. A user defined operator is a custom VTL operator (not existing in the standard library) that extends the VTL standard library for specific purposes. In addition to its identification and name, and definition of the operator must be provided. + + + + + + + A VTL statement for the definition of a new operator: it specifies the operator name, its parameters and their data types, the VTL expression that defines its behaviour. + + + + + + + + + + CustomTypeSchemeType defines a collection of custom types that are used in transformations. + + + + + + + + + + + + + + + + + + + + CustomType details a custom type within a custom type scheme. + + + + + + CustomTypeBaseType defines the base refinement of the CustomTypeType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + CustomTypeType defines the structure of a custom type. A custom type specifies a custom conversion for a VTL scalar type to a resulting data type. This conversion overrides the default conversion. + + + + + + + Identifies the VTL scalar type that is to be converted to an resulting output data type. + + + + + Identifies the resulting output data type the VTL scalar type is to be converted to. If this is an SDMX data type, it must use the proper SimpleDataType enumeration value. For all other data types, a string value can be used to identify the type. + + + + + The format in which the literals of the VTL scalar type are expressed in the transformations. This is only needed if the format is different than the output format expressed by means of the VTL type. + + + + + The format the VTL scalar type has to assume (e.g. YYYY-MM-DD; see VTL specifications), both for the literals in the VTL expressions and for the conversion to the output. + + + + + The value to be produced in the output of the conversion when a component has a null value. + + + + + + + + + + A simple type that allows for a SDMX simple data type enumeration value or a string value for other data types. + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/codelist.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/codelist.xsd new file mode 100644 index 0000000..550bbad --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/codelist.xsd @@ -0,0 +1,365 @@ + + + + + + + + SDMX Code List Structure Module + The code list structure module defines the structure of code list and code constructs. + + + + + CodelistType defines the structure of a codelist. A codelist is defined as a list from which some statistical concepts (coded concepts) take their values. + + + + + + + + + + + + + + + + The id attribute holds the identification of the code list. The type of this id is restricted to the common:NCNNameIDType. This is necessary, since the code list may be used to create simple types in data and metadata structure specific schemas and therefore must be compliant with the NCName type in XML Schema (see common:NCNameIDType for further details). + + + + + + + + + + + + + CodelistExtension allows for the extension of codelists by referencing the codelists to be extended and providing inclusion/exclusion rules for selecting the codes to extend. The order of these is important as it is indicates the order of precedence of the extended codelists for conflict resolution of codes. However, the prefix property can be used to ensure uniqueness of inherited codes in the extending codelist, in case conflicting codes must be included. + + + + + + + + + + Code describes a code in a codelist. In addition to the identification and description of the code, basic presentational information is also available. Presentational information not present may be added through the use of annotations. + + + + + + CodeType describes the structure of a code. A code is defined as a language independent set of letters, numbers or symbols that represent a concept whose meaning is described in a natural language. Presentational information not present may be added through the use of annotations. + + + + + + + + + Name provides for a human-readable name for the object. This may be provided in multiple, parallel language-equivalent forms. It may be used in place of a short description. + + + + + Description provides a plain text, human-readable description of the code. This may be provided in multiple, parallel language-equivalent forms. + + + + + + Parent provides the ability to describe simple hierarchies within a single codelist, by referencing the id value of another code in the same codelist. + + + + + + + + + + + + CodelistExtensionType defines the structure of a codelist to be extended by the codelist defining the extension. It provides a reference to the extended codelist and selection criteria to indicate the codes to be included in the extending codelist. + + + + + + + Selection of codes from the referenced (extended) codelist to be included in the extending codelist. + + + + + Selection of codes from the referenced (extended) codelist to be excluded in the extending codelist. + + + + + + + A reference to a codelist may contain a prefix. If a prefix is provided, this prefix will be applied to all the codes in the codelist before they are imported into the extended codelist. + + + + + + + CodeSelectionType defines the structure for code selection to be used as inclusive or exclusive extensions. + + + + + An explicit or wildcard selection of a code(s) from the codelist selected for inclusion/exclusion. If a wildcard expression is used, it is evaluated to determine codes selected for inclusion/exclusion. Otherwise, each member value is a distinct code. If the extended list is hierarchical, this can indicate whether child codes are to be included. + + + + + + + + + WildcardedMemberValueType allows for an optional wildcard characters ('%') in an identifier. + + + + + + + + + Allows for a ditinct reference or a wildcard expression for selecting codes from a codelist. + + + + + + Indicates whether child codes should be selected when the codelist is hierarchical. Possible values are true (include the selected and child codes), false (only include the selected code(s)), and excluderoot (include the children but not the selected code(s)). + + + + + + + + + GeoCodelistBaseType is an abstract base refinement of a codelist that restricts the cods to be derived from the abstract GeoRefCode. + + + + + + + + + + + + + + + + + + + + GeoCodelistType is an abstract refinement of a codelist from which specific types of geographic codelists will be derived. + + + + + + The type of geographic codelist. The will be refined and provided a fixed value in the specific geographic codelist type implementations. + + + + + + + + + GeoRefCode is the abstract base from which specific types of geographic codes will be derived. + + + + + + GeoRefCodeType is the abstract base type defining the structure of geographic codes. + + + + + + + + + GeographicCodelistType defines the sturcture of a geographic codelist. It comprises a set of GeoFeatureSetCodes, by adding a value in the Code that follows a pattern to represent a geo feature set. + + + + + + + + + + + + + + + + + + + + + Is a geographic code in a geographic codelist. It adds a value to a code that folows a pattern to represent a geo feature set. + + + + + + GeoFeatureSetCodeType defines the structure of a geogrphic code. + + + + + + The geo feature set of the Code, which represents a set of points defining a feature in a format defined a predefined pattern (see section 6). + + + + + + + + + GeoGridCodelistBaseType is the abstract base refinement for a geographic grid codelist. + + + + + + + + + + + + + + + + + + + + + GeoGridCodelistType defines the structure of a geographic grid code list. These define a geographical grid composed of cells representing regular squared portions of the Earth. + + + + + + + Contains a regular expression string corresponding to the grid definition for the GeoGrid Codelist. + + + + + + + + + + GeoGridCode is a code the represents a geographic grid cell that belongs to a specific grid definition. + + + + + + GeoGridCodeType defines the structure of a geographic grid cell. + + + + + + + The value used to assign the Code to one cell in the grid. + + + + + + + + + + GeoCodelistTypeType defines an enumeration of the speicfic types of geographic codelists. + + + + + + + + + + ValueListBaseType defines the base refinement of the ValueListType. Its purpose is to retrict the urn attribute. + + + + + + + + + + + + + + + + + ValueListType defines the structure of value list. These represent a closed set of values the can occur for a dimension, measure, or attribute. These may be values, or values with names and descriptions (similar to a codelist). + + + + + + + + + + + + + + + + + ValueItemType defines the structure of a value item. A value must be provided, and a longer name and description can be provided to provide additiona meaning to the value (similar to a code in a code list). + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdmx-ml30/src/test/resources/xml/xsd/schemas/xml.xsd b/sdmx-ml30/src/test/resources/xml/xsd/schemas/xml.xsd new file mode 100644 index 0000000..9294f94 --- /dev/null +++ b/sdmx-ml30/src/test/resources/xml/xsd/schemas/xml.xsd @@ -0,0 +1,80 @@ + + + + + + See http://www.w3.org/XML/1998/namespace.html and + http://www.w3.org/TR/REC-xml for information about this namespace. + + + + + This schema defines attributes and an attribute group + suitable for use by + schemas wishing to allow xml:base, xml:lang or xml:space attributes + on elements they define. + + To enable this, such a schema must import this schema + for the XML namespace, e.g. as follows: + <schema . . .> + . . . + <import namespace="http://www.w3.org/XML/1998/namespace" + schemaLocation="http://www.w3.org/2001/03/xml.xsd"/> + + Subsequently, qualified reference to any of the attributes + or the group defined below will have the desired effect, e.g. + + <type . . .> + . . . + <attributeGroup ref="xml:specialAttrs"/> + + will define a type which will schema-validate an instance + element with any of those attributes + + + + In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + http://www.w3.org/2001/03/xml.xsd. + At the date of issue it can also be found at + http://www.w3.org/2001/xml.xsd. + The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML Schema + itself. In other words, if the XML Schema namespace changes, the version + of this document at + http://www.w3.org/2001/xml.xsd will change + accordingly; the version at + http://www.w3.org/2001/03/xml.xsd will not change. + + + + + + In due course, we should install the relevant ISO 2- and 3-letter + codes as the enumerated possible values . . . + + + + + + + + + + + + + + + See http://www.w3.org/TR/xmlbase/ for + information about this attribute. + + + + + + + + + + diff --git a/sdmx30-serializer/build.gradle b/sdmx30-serializer/build.gradle new file mode 100644 index 0000000..1e179ec --- /dev/null +++ b/sdmx30-serializer/build.gradle @@ -0,0 +1,46 @@ +plugins { + id 'java' +} + +repositories { + mavenCentral() +} + +dependencies { + compileOnly("org.projectlombok:lombok:${lombok_version}") + annotationProcessor("org.projectlombok:lombok:${lombok_version}") + + implementation project(":sdmx30-infomodel") + + implementation("org.apache.logging.log4j:log4j-slf4j2-impl:${log4j_version}") + implementation("org.apache.logging.log4j:log4j-core:${log4j_version}") + implementation("com.epam.deltix:SdmxDataParser:${sdmx_version}") + + implementation("org.mapstruct:mapstruct:${mapstruct_version}") + annotationProcessor("org.mapstruct:mapstruct-processor:${mapstruct_version}") + + implementation("org.apache.commons:commons-collections4:${org_apache_commons_commons_collections4_version}") + implementation("org.apache.commons:commons-lang3:${org_apache_commons_commons_lang3_version}") + implementation("com.fasterxml.jackson.core:jackson-core:${fasterxml_version}") + implementation("com.fasterxml.jackson.core:jackson-databind:${fasterxml_databind_version}") + implementation("com.google.guava:guava:${guava_version}") + implementation "com.opencsv:opencsv:${openc_csv_version}" + + + testImplementation("org.projectlombok:lombok:${lombok_version}") + testAnnotationProcessor("org.projectlombok:lombok:${lombok_version}") + + testImplementation("org.jsonschema2pojo:jsonschema2pojo-core:${jsonschema2pojo_version}") + testImplementation("io.github.benas:random-beans:${random_beans_version}") + testImplementation("org.assertj:assertj-core:${assertj_version}") + testImplementation("net.javacrumbs.json-unit:json-unit:${json_unit_version}") + testImplementation("net.javacrumbs.json-unit:json-unit-assertj:${json_unit_version}") + testImplementation("org.mockito:mockito-core:${mockito_version}") + testImplementation("org.xmlunit:xmlunit-legacy:${xmlunit_legacy_version}") + + implementation("org.glassfish.jaxb:jaxb-runtime:${xml_bind_jaxb_version}") +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/common/ReferenceAdapter.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/common/ReferenceAdapter.java new file mode 100644 index 0000000..4055051 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/common/ReferenceAdapter.java @@ -0,0 +1,18 @@ +package com.epam.jsdmx.serializer.common; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.infomodel.sdmx30.StructureClass; + +public interface ReferenceAdapter { + String adaptUrn(String urn); + + String toAdaptedUrn(ArtefactReference ref); + + default String adaptType(String type) { + return type; + } + + default StructureClass adaptType(StructureClass type) { + return type; + } +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/common/StubDataStructureLocalRepresentationAdapter.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/common/StubDataStructureLocalRepresentationAdapter.java new file mode 100644 index 0000000..8b4ec48 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/common/StubDataStructureLocalRepresentationAdapter.java @@ -0,0 +1,9 @@ +package com.epam.jsdmx.serializer.common; + +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinition; + +public class StubDataStructureLocalRepresentationAdapter implements TimeDimensionLocalRepresentationAdapter { + public DataStructureDefinition adapt(DataStructureDefinition dsd) { + return dsd; + } +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/common/TimeDimensionLocalRepresentationAdapter.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/common/TimeDimensionLocalRepresentationAdapter.java new file mode 100644 index 0000000..6fc7a02 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/common/TimeDimensionLocalRepresentationAdapter.java @@ -0,0 +1,7 @@ +package com.epam.jsdmx.serializer.common; + +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinition; + +public interface TimeDimensionLocalRepresentationAdapter { + DataStructureDefinition adapt(DataStructureDefinition dsd); +} \ No newline at end of file diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/DataStructure30To21ComponentAdapter.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/DataStructure30To21ComponentAdapter.java new file mode 100644 index 0000000..62f2597 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/DataStructure30To21ComponentAdapter.java @@ -0,0 +1,7 @@ +package com.epam.jsdmx.serializer.sdmx21; + +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinition; + +public interface DataStructure30To21ComponentAdapter { + DataStructureDefinition recompose(DataStructureDefinition dsd); +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/DataStructure30To21ComponentAdapterImpl.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/DataStructure30To21ComponentAdapterImpl.java new file mode 100644 index 0000000..b3aacfe --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/DataStructure30To21ComponentAdapterImpl.java @@ -0,0 +1,136 @@ +package com.epam.jsdmx.serializer.sdmx21; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.AttributeDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataAttribute; +import com.epam.jsdmx.infomodel.sdmx30.DataAttributeImpl; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinition; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinitionImpl; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.DimensionDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.Measure; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptor; +import com.epam.jsdmx.infomodel.sdmx30.MeasureDescriptorImpl; +import com.epam.jsdmx.infomodel.sdmx30.MeasureImpl; +import com.epam.jsdmx.infomodel.sdmx30.ObservationRelationshipImpl; + +import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; + +@RequiredArgsConstructor +public class DataStructure30To21ComponentAdapterImpl implements DataStructure30To21ComponentAdapter { + + private static final String OBS_VALUE = "OBS_VALUE"; + + private final MetadataConverter metadataConverter; + + @Override + public DataStructureDefinition recompose(DataStructureDefinition dsd) { + var dsdCopy = new DataStructureDefinitionImpl(dsd); + dsdCopy.setMeasureDescriptor(withSingleMeasure(dsd.getMeasureDescriptor())); + dsdCopy.setDimensionDescriptor(copy(dsd.getDimensionDescriptor())); + dsdCopy.setAttributeDescriptor(combinedAttributesMetaAndMeasures(dsd)); + return dsdCopy; + } + + private DimensionDescriptorImpl copy(DimensionDescriptor dimensionDescriptor) { + if (dimensionDescriptor == null) { + return null; + } + var descriptor = new DimensionDescriptorImpl(); + descriptor.setId(dimensionDescriptor.getId()); + descriptor.setAnnotations(dimensionDescriptor.getAnnotations()); + descriptor.setUri(dimensionDescriptor.getUri()); + descriptor.setContainer(dimensionDescriptor.getContainer()); + descriptor.setComponents(new ArrayList<>(dimensionDescriptor.getComponents())); + return descriptor; + } + + private MeasureDescriptorImpl withSingleMeasure(MeasureDescriptor measureDescriptor) { + if (measureDescriptor == null) { + return null; + } + var descriptor = new MeasureDescriptorImpl(); + descriptor.setId(measureDescriptor.getId()); + descriptor.setAnnotations(measureDescriptor.getAnnotations()); + descriptor.setUri(measureDescriptor.getUri()); + descriptor.setContainer(measureDescriptor.getContainer()); + descriptor.setComponents(extractFirstMeasure(measureDescriptor.getComponents())); + return descriptor; + } + + private AttributeDescriptorImpl combinedAttributesMetaAndMeasures(DataStructureDefinition dsd) { + if (dsd.getAttributeDescriptor() == null) { + return null; + } + var attributeDescriptor = dsd.getAttributeDescriptor(); + var descriptor = new AttributeDescriptorImpl(); + descriptor.setId(attributeDescriptor.getId()); + descriptor.setAnnotations(attributeDescriptor.getAnnotations()); + descriptor.setUri(attributeDescriptor.getUri()); + descriptor.setContainer(attributeDescriptor.getContainer()); + descriptor.setComponents(getCombinedAttributes(dsd)); + return descriptor; + } + + private List getCombinedAttributes(DataStructureDefinition dsd) { + List dataAttributes = dsd.getDataAttributes(); + List metaAttributes = metadataConverter.convertMetaAttributesToData(dsd); + List measuresAsAttributes = convertMeasuresToAttributes(dsd.getMeasureDescriptor()); + + var result = new ArrayList<>(dataAttributes); + result.addAll(metaAttributes); + result.addAll(measuresAsAttributes); + + return result; + } + + private List convertMeasuresToAttributes(MeasureDescriptor measureDescriptor) { + List measures = measureDescriptor.getComponents(); + + if (CollectionUtils.size(measures) < 2) { + return List.of(); + } + + Measure measureToSkip = measures.stream() + .filter(measure -> OBS_VALUE.equals(measure.getId())) + .findFirst() + .orElse(measures.get(0)); + + return measures.stream() + .filter(measure -> !measure.getId().equals(measureToSkip.getId())) + .map(this::convertMeasureToAttribute) + .collect(Collectors.toList()); + } + + private DataAttribute convertMeasureToAttribute(Measure measure) { + var a = new DataAttributeImpl(); + a.setId(measure.getId()); + a.setLocalRepresentation(measure.getLocalRepresentation()); + a.setConceptIdentity(measure.getConceptIdentity()); + a.setAttributeRelationship(new ObservationRelationshipImpl()); + a.setAnnotations(measure.getAnnotations()); + a.setContainer(measure.getContainer()); + return a; + } + + private List extractFirstMeasure(List measures) { + if (CollectionUtils.isEmpty(measures)) { + return new ArrayList<>(0); + } + + for (Measure measure : measures) { + if (measure.getId().equals(OBS_VALUE)) { + return new ArrayList<>(List.of(measure)); + } + } + + var firstMeasure = new MeasureImpl(measures.get(0)); + firstMeasure.setId(OBS_VALUE); + return new ArrayList<>(List.of(firstMeasure)); + + } +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/MetadataConverter.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/MetadataConverter.java new file mode 100644 index 0000000..1bc270e --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/MetadataConverter.java @@ -0,0 +1,10 @@ +package com.epam.jsdmx.serializer.sdmx21; + +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.DataAttribute; +import com.epam.jsdmx.infomodel.sdmx30.DataStructureDefinition; + +public interface MetadataConverter { + List convertMetaAttributesToData(DataStructureDefinition dsd); +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/ReferenceResolver.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/ReferenceResolver.java new file mode 100644 index 0000000..e655830 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx21/ReferenceResolver.java @@ -0,0 +1,11 @@ +package com.epam.jsdmx.serializer.sdmx21; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; + +/** + * Resolves wildcarded references, i.e. having wildcarded version (1.0.0+, 1.0+.0, 1+.0.0, etc.) + */ +@FunctionalInterface +public interface ReferenceResolver { + ArtefactReference resolve(ArtefactReference reference); +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/ActionType.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/ActionType.java new file mode 100644 index 0000000..192f14e --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/ActionType.java @@ -0,0 +1,46 @@ +package com.epam.jsdmx.serializer.sdmx30.common; + +import static org.apache.commons.lang3.EnumUtils.getEnumIgnoreCase; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * An optional parameter which allows the user to specify the value of + * the DataSetAction generated in the validation report. + * If this parameter is not specified, the default value will be used. + */ +@RequiredArgsConstructor +@Getter +public enum ActionType { + /** + * Information - Data is for information purposes. If such data messages + * are loaded into an SDMX database, the action "A" (Append) is assumed. + */ + INFORMATION("Information"), + + /** + * Append - Data is for an incremental update of existing observations or + * partial-key attributes or for the provision of new data formerly absent. + * This means that only the information provided explicitly in the message should be altered. + */ + APPEND("Append"), + + /** + * Replace - Data is for replacement. Existing observations are to be fully replaced. + * Existing attribute values are to be replaced. + * Observations or attribute values formally absent will be appended. + */ + REPLACE("Replace"), + + /** + * Data is to be deleted. 'Delete' is assumed to be an incremental deletion. + */ + DELETE("Delete"); + + private final String value; + + public static ActionType valueOfIgnoreCase(String value) { + return getEnumIgnoreCase(ActionType.class, value); + } +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DataLocation.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DataLocation.java new file mode 100644 index 0000000..f838b67 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DataLocation.java @@ -0,0 +1,9 @@ +package com.epam.jsdmx.serializer.sdmx30.common; + +import java.io.InputStream; + +public interface DataLocation { + + InputStream inputStream(); + +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DataWriter.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DataWriter.java new file mode 100644 index 0000000..1a54388 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DataWriter.java @@ -0,0 +1,36 @@ +package com.epam.jsdmx.serializer.sdmx30.common; + +import java.util.List; +import java.util.Map; + +import com.epam.jsdmx.infomodel.sdmx30.Annotation; +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; + +public interface DataWriter extends AutoCloseable { + void startDataset(ProvisionAgreement agreement, Artefacts artefacts, DatasetHeader header); + + void startSeries(Annotation... annotations); + + void writeSeriesComponent(String concept, String code); + + void startGroup(Annotation... annotations); + + void writeGroupComponent(String concept, String code); + + void writeObservation(String obsConceptValue, Map measureValues, Annotation[] annotations30); + + void writeObservation(String dimAtObsForWrite, String obsConceptValue, Map measureValues, Annotation[] annotations30); + + void writeAttribute(String concept, String code); + + void writeAttribute(String concept, List code); + + void writeAttribute(String concept, InternationalString value); + + void writeInternationalAttributes(String concept, List value); + + void writeMetaData(MetadataAttributeValue metadataAttributeValue); + + void close(); +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetHeader.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetHeader.java new file mode 100644 index 0000000..22e538c --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetHeader.java @@ -0,0 +1,69 @@ +package com.epam.jsdmx.serializer.sdmx30.common; + +import java.time.Instant; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; + +/** + * Data collected in order to write dataset information + */ +public interface DatasetHeader { + + /** + * @return Corresponding ID of a Dataset + */ + String getDatasetId(); + + /** + * @return Defines the action to be taken by the recipient system + * (information, append, replace, delete) + */ + ActionType getAction(); + + /** + * @return Reference to data structure + */ + DatasetStructureReference getDatasetStructureReference(); + + /** + * @return Associates the Data Provider that reports/publishes the data + */ + ArtefactReference getProviderReference(); + + /** + * @return A specific time period in a known system of time periods + * that identifies the start period of a report. + */ + Instant getReportingBeginDate(); + + /** + * @return A specific time period in a known system of time periods + * that identifies the end period of a report. + */ + Instant getReportingEndDate(); + + /** + * @return Date from which the DatasetHeader is valid. + */ + Instant getValidFrom(); + + /** + * @return Date from which DatasetHeader is superseded. + */ + Instant getValidTo(); + + /** + * @return Specifies the year of publication of the data + */ + int getPublicationYear(); + + /** + * @return Specifies the period of publication of the data + */ + String getPublicationPeriod(); + + /** + * @return Specifies the year of publication of the data + */ + String getReportingYearStartDate(); +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetHeaderImpl.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetHeaderImpl.java new file mode 100644 index 0000000..f10cba5 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetHeaderImpl.java @@ -0,0 +1,24 @@ +package com.epam.jsdmx.serializer.sdmx30.common; + +import java.time.Instant; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class DatasetHeaderImpl implements DatasetHeader { + private final String datasetId; + private final ActionType action; + private final DatasetStructureReference datasetStructureReference; + private final ArtefactReference providerReference; + private final Instant reportingBeginDate; + private final Instant reportingEndDate; + private final Instant validFrom; + private final Instant validTo; + private int publicationYear = -1; + private String publicationPeriod; + private String reportingYearStartDate; +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetStructureReference.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetStructureReference.java new file mode 100644 index 0000000..9a01b4c --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetStructureReference.java @@ -0,0 +1,27 @@ +package com.epam.jsdmx.serializer.sdmx30.common; + + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; + +/** + * Contains the identification of a dataset object. + * Reference to a data structure + */ +public interface DatasetStructureReference { + + /** + * @return Reference to a structure + */ + ArtefactReference getDataStructureReference(); + + /** + * @return Defines the action to be taken by the recipient system + * (information, append, replace, delete) + */ + ActionType getAction(); + + /** + * @return The value for the 'Dimension at the Observation Level' + */ + String getDimensionAtObservation(); +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetStructureReferenceImpl.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetStructureReferenceImpl.java new file mode 100644 index 0000000..6de8f37 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DatasetStructureReferenceImpl.java @@ -0,0 +1,14 @@ +package com.epam.jsdmx.serializer.sdmx30.common; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public class DatasetStructureReferenceImpl implements DatasetStructureReference { + private final ArtefactReference dataStructureReference; + private final ActionType action; + private final String dimensionAtObservation; +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DefaultHeaderProvider.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DefaultHeaderProvider.java new file mode 100644 index 0000000..0c3b145 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DefaultHeaderProvider.java @@ -0,0 +1,54 @@ +package com.epam.jsdmx.serializer.sdmx30.common; + +import java.net.URI; +import java.time.Instant; +import java.util.List; +import java.util.Locale; + +import com.epam.jsdmx.infomodel.sdmx30.DefaultLocaleHolder; +import com.epam.jsdmx.infomodel.sdmx30.Party; + +import lombok.SneakyThrows; +import org.apache.commons.lang3.RandomUtils; + +public class DefaultHeaderProvider { + + /** + * This constant holds the Schema ID. Currently, Schema ID is different from the real + * + * sdmx-json-metadata-schema.json + * storage address. + * In other words, Schema ID stored in this constant should match to ID provided inside + * + * sdmx-json-metadata-schema.json. + */ + public static final String SCHEMA + = "https://raw.githubusercontent.com/sdmx-twg/sdmx-json/master/metadata-message/tools/schemas/2.0.0/sdmx-json-metadata-schema.json"; + + @SneakyThrows + public Header provide() { + Header header = new Header(); + header.setSchema(new URI(SCHEMA)); + header.setId(generateId()); + header.setContentLanguages(getDefaultLocales()); + header.setTest(false); + header.setPrepared(Instant.now()); + header.setSender(generateUnknownParty()); + return header; + } + + private String generateId() { + return "IDREF" + RandomUtils.nextInt(1000, 9999); + } + + private Party generateUnknownParty() { + return Party.builder() + .id("unknown") + .build(); + } + + private List getDefaultLocales() { + return List.of(DefaultLocaleHolder.INSTANCE.get()); + } + +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DefaultReferenceAdapter.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DefaultReferenceAdapter.java new file mode 100644 index 0000000..1b50c2c --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/DefaultReferenceAdapter.java @@ -0,0 +1,16 @@ +package com.epam.jsdmx.serializer.sdmx30.common; + +import com.epam.jsdmx.infomodel.sdmx30.ArtefactReference; +import com.epam.jsdmx.serializer.common.ReferenceAdapter; + +public class DefaultReferenceAdapter implements ReferenceAdapter { + @Override + public String adaptUrn(String urn) { + return urn; + } + + @Override + public String toAdaptedUrn(ArtefactReference ref) { + return ref != null ? ref.getUrn() : null; + } +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/Header.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/Header.java new file mode 100644 index 0000000..a2e23d9 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/Header.java @@ -0,0 +1,35 @@ +package com.epam.jsdmx.serializer.sdmx30.common; + + +import java.net.URI; +import java.time.Instant; +import java.util.List; +import java.util.Locale; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; +import com.epam.jsdmx.infomodel.sdmx30.Party; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Base type that defines the basis for all message headers + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class Header { + + private URI schema; + private String id; + private boolean test; + private Instant prepared; + private List contentLanguages; + private InternationalString name; + private Party sender; + private List receivers; + +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/InMemoryDataLocation.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/InMemoryDataLocation.java new file mode 100644 index 0000000..936eac2 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/InMemoryDataLocation.java @@ -0,0 +1,22 @@ +package com.epam.jsdmx.serializer.sdmx30.common; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class InMemoryDataLocation implements DataLocation { + + private final byte[] bytes; + + public InMemoryDataLocation(String source) { + this.bytes = source.getBytes(StandardCharsets.UTF_8); + } + + @Override + public InputStream inputStream() { + return new ByteArrayInputStream(bytes); + } +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/MetadataAttributeValue.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/MetadataAttributeValue.java new file mode 100644 index 0000000..5290857 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/MetadataAttributeValue.java @@ -0,0 +1,28 @@ +package com.epam.jsdmx.serializer.sdmx30.common; + +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; + +public interface MetadataAttributeValue { + /** + * @return id of the attribute + */ + String getId(); + + /** + * @return string representation of the underlying data type + */ + List getStringValues(); + + /** + * @return localised values + */ + List getLocalisedValues(); + + /** + * @return the children of the attribute + */ + List getChildren(); + +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/MultilingualMetadataAttributeValue.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/MultilingualMetadataAttributeValue.java new file mode 100644 index 0000000..b9dd506 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/MultilingualMetadataAttributeValue.java @@ -0,0 +1,48 @@ +package com.epam.jsdmx.serializer.sdmx30.common; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; + +import lombok.Data; +import org.apache.commons.collections4.ListUtils; + +@Data +public class MultilingualMetadataAttributeValue implements MetadataAttributeValue { + + private String id; + private List values; + private List children; + + public MultilingualMetadataAttributeValue() { + values = new ArrayList<>(); + children = new ArrayList<>(); + } + + public MultilingualMetadataAttributeValue(String id, + List values, + List children) { + this.id = id; + this.values = values; + this.children = children; + } + + @Override + public List getStringValues() { + return getLocalisedValues().stream() + .map(InternationalString::getForDefaultLocale) + .collect(Collectors.toList()); + } + + @Override + public List getLocalisedValues() { + return ListUtils.emptyIfNull(values); + } + + @Override + public List getChildren() { + return children; + } +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/ProvisionAgreement.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/ProvisionAgreement.java new file mode 100644 index 0000000..8524f73 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/ProvisionAgreement.java @@ -0,0 +1,12 @@ +package com.epam.jsdmx.serializer.sdmx30.common; + +import com.epam.jsdmx.infomodel.sdmx30.ConstrainableArtefact; + +/** + * A ProvisionAgreement links the artefact that defines + * how data are structured and classified (StructureUsage) to the DataProvider. + * The agreement may constrain the scope of the data that can be provided, by means + * of a DataConstraint. + */ +public interface ProvisionAgreement extends ConstrainableArtefact { +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/SimpleMetadataAttributeValue.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/SimpleMetadataAttributeValue.java new file mode 100644 index 0000000..2f8ca3a --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/common/SimpleMetadataAttributeValue.java @@ -0,0 +1,51 @@ +package com.epam.jsdmx.serializer.sdmx30.common; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.epam.jsdmx.infomodel.sdmx30.InternationalString; + +import lombok.Data; +import org.apache.commons.collections4.ListUtils; + +@Data +public class SimpleMetadataAttributeValue implements MetadataAttributeValue { + private String id; + private List values; + private List children; + + public SimpleMetadataAttributeValue() { + values = new ArrayList<>(); + children = new ArrayList<>(); + } + + public SimpleMetadataAttributeValue(String id, + List values, + List children) { + this.id = id; + this.values = values; + this.children = children; + } + + public boolean isEmpty(SimpleMetadataAttributeValue metadataAttributeValue) { + return metadataAttributeValue.getValues().isEmpty(); + } + + @Override + public String getId() { + return id; + } + + @Override + public List getStringValues() { + return ListUtils.emptyIfNull(values); + } + + @Override + public List getLocalisedValues() { + return getStringValues().stream() + .map(InternationalString::new) + .collect(Collectors.toList()); + } +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/structure/StructureReader.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/structure/StructureReader.java new file mode 100644 index 0000000..8c7d8f3 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/structure/StructureReader.java @@ -0,0 +1,11 @@ +package com.epam.jsdmx.serializer.sdmx30.structure; + + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; +import com.epam.jsdmx.serializer.sdmx30.common.DataLocation; + +public interface StructureReader { + + Artefacts read(DataLocation location); + +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/structure/StructureWriter.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/structure/StructureWriter.java new file mode 100644 index 0000000..4066fb9 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/sdmx30/structure/StructureWriter.java @@ -0,0 +1,9 @@ +package com.epam.jsdmx.serializer.sdmx30.structure; + +import com.epam.jsdmx.infomodel.sdmx30.Artefacts; + +public interface StructureWriter { + + void write(Artefacts artefacts); + +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/util/DateTimeConverterUtil.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/util/DateTimeConverterUtil.java new file mode 100644 index 0000000..b054053 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/util/DateTimeConverterUtil.java @@ -0,0 +1,13 @@ +package com.epam.jsdmx.serializer.util; + +import org.apache.commons.lang3.StringUtils; + +public class DateTimeConverterUtil { + public static String convertToDateTime(String date) { + if (StringUtils.isBlank(date) || date.contains("T")) { + return date; + } + + return date + "T00:00:00Z"; + } +} diff --git a/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/util/DimensionUtil.java b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/util/DimensionUtil.java new file mode 100644 index 0000000..00f9af3 --- /dev/null +++ b/sdmx30-serializer/src/main/java/com/epam/jsdmx/serializer/util/DimensionUtil.java @@ -0,0 +1,17 @@ +package com.epam.jsdmx.serializer.util; + +import java.util.List; + +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponent; +import com.epam.jsdmx.infomodel.sdmx30.DimensionComponentImpl; + +public final class DimensionUtil { + private DimensionUtil() { } + + public static void populateZeroBasedOrder(List dimensionComponents) { + for (int i = 0; i < dimensionComponents.size(); i++) { + var dimensionComponent = (DimensionComponentImpl) dimensionComponents.get(i); + dimensionComponent.setOrder(i); + } + } +} diff --git a/settings.gradle b/settings.gradle index 0c8d9bc..b63cc00 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,8 @@ rootProject.name = 'jsdmx' include ':sdmx30-infomodel' +include ':sdmx-ml30' +include ':sdmx-json20' +include ':sdmx30-serializer' +include ':sdmx-json10' +include ':sdmx-ml21' From fb0a349efc3572da0934e6c867728db10cee74a8 Mon Sep 17 00:00:00 2001 From: Ivan Yakubenko Date: Thu, 8 Jan 2026 14:55:51 +0200 Subject: [PATCH 2/4] change version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 187f619..734d2f3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ group=com.epam.jsdmx -version=1.0.0-SNAPSHOT +version=2.0.0-SNAPSHOT #dependencies jupiter_version=5.8.2 From 2940f23ffeb5f1ebcad62d032855ac87795756a4 Mon Sep 17 00:00:00 2001 From: Ivan Yakubenko Date: Thu, 8 Jan 2026 16:26:03 +0200 Subject: [PATCH 3/4] update dependencies --- build.gradle | 3 +++ gradle.properties | 5 ++--- sdmx-json10/build.gradle | 3 --- sdmx-json20/build.gradle | 3 --- sdmx-ml21/build.gradle | 3 --- sdmx-ml30/build.gradle | 3 --- sdmx30-infomodel/build.gradle | 2 -- sdmx30-serializer/build.gradle | 3 --- 8 files changed, 5 insertions(+), 20 deletions(-) diff --git a/build.gradle b/build.gradle index 237e9de..7943072 100644 --- a/build.gradle +++ b/build.gradle @@ -122,6 +122,9 @@ subprojects { compileOnly("org.projectlombok:lombok:${lombok_version}") annotationProcessor("org.projectlombok:lombok:${lombok_version}") + implementation("org.apache.commons:commons-collections4:${org_apache_commons_commons_collections4_version}") + implementation("org.apache.commons:commons-lang3:${org_apache_commons_commons_lang3_version}") + testImplementation("org.junit.jupiter:junit-jupiter-api:${jupiter_version}") testImplementation("org.junit.jupiter:junit-jupiter-params:${jupiter_version}") testImplementation("org.assertj:assertj-core:${assertj_version}") diff --git a/gradle.properties b/gradle.properties index 734d2f3..0e37e71 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,15 +10,14 @@ jupiter_api_version=5.11.4 jupiter_engine_version=5.11.4 mockito_version=5.4.0 json_unit_version=4.1.1 -spring_version=6.2.10 -log4j_version=2.24.3 +spring_version=6.2.11 +log4j_version=2.25.3 sdmx_version=2.0.6 mapstruct_version=1.5.3.Final fasterxml_version=2.18.4 fasterxml_databind_version=2.18.4 guava_version=33.0.0-jre openc_csv_version=5.12.0 -random_beans_version=3.9.0 jsonschema2pojo_version=1.2.2 junit_version=4.13.2 assertj_version=3.26.3 diff --git a/sdmx-json10/build.gradle b/sdmx-json10/build.gradle index 39a8878..bf5ae0f 100644 --- a/sdmx-json10/build.gradle +++ b/sdmx-json10/build.gradle @@ -17,8 +17,6 @@ dependencies { implementation("org.apache.logging.log4j:log4j-core:${log4j_version}") implementation("com.epam.deltix:SdmxDataParser:${sdmx_version}") - implementation("org.apache.commons:commons-collections4:${org_apache_commons_commons_collections4_version}") - implementation("org.apache.commons:commons-lang3:${org_apache_commons_commons_lang3_version}") implementation("com.fasterxml.jackson.core:jackson-core:${fasterxml_version}") implementation("com.fasterxml.jackson.core:jackson-databind:${fasterxml_databind_version}") implementation("com.google.guava:guava:${guava_version}") @@ -27,7 +25,6 @@ dependencies { testAnnotationProcessor("org.projectlombok:lombok:${lombok_version}") testImplementation("org.jsonschema2pojo:jsonschema2pojo-core:${jsonschema2pojo_version}") - testImplementation("io.github.benas:random-beans:${random_beans_version}") testImplementation("org.assertj:assertj-core:${assertj_version}") testImplementation("net.javacrumbs.json-unit:json-unit:${json_unit_version}") testImplementation("net.javacrumbs.json-unit:json-unit-assertj:${json_unit_version}") diff --git a/sdmx-json20/build.gradle b/sdmx-json20/build.gradle index 4941ebe..26fc84f 100644 --- a/sdmx-json20/build.gradle +++ b/sdmx-json20/build.gradle @@ -21,8 +21,6 @@ dependencies { implementation("org.mapstruct:mapstruct:${mapstruct_version}") annotationProcessor("org.mapstruct:mapstruct-processor:${mapstruct_version}") - implementation("org.apache.commons:commons-collections4:${org_apache_commons_commons_collections4_version}") - implementation("org.apache.commons:commons-lang3:${org_apache_commons_commons_lang3_version}") implementation("com.fasterxml.jackson.core:jackson-core:${fasterxml_version}") implementation("com.fasterxml.jackson.core:jackson-databind:${fasterxml_databind_version}") implementation("com.google.guava:guava:${guava_version}") @@ -32,7 +30,6 @@ dependencies { testAnnotationProcessor("org.projectlombok:lombok:${lombok_version}") testImplementation("org.jsonschema2pojo:jsonschema2pojo-core:${jsonschema2pojo_version}") - testImplementation("io.github.benas:random-beans:${random_beans_version}") testImplementation("org.assertj:assertj-core:${assertj_version}") testImplementation("net.javacrumbs.json-unit:json-unit:${json_unit_version}") testImplementation("net.javacrumbs.json-unit:json-unit-assertj:${json_unit_version}") diff --git a/sdmx-ml21/build.gradle b/sdmx-ml21/build.gradle index 6cd7227..7a2e9cb 100644 --- a/sdmx-ml21/build.gradle +++ b/sdmx-ml21/build.gradle @@ -19,8 +19,6 @@ dependencies { implementation("org.apache.logging.log4j:log4j-core:${log4j_version}") implementation("com.epam.deltix:SdmxDataParser:${sdmx_version}") implementation("org.mapstruct:mapstruct:${mapstruct_version}") - implementation("org.apache.commons:commons-collections4:${org_apache_commons_commons_collections4_version}") - implementation("org.apache.commons:commons-lang3:${org_apache_commons_commons_lang3_version}") implementation("com.fasterxml.jackson.core:jackson-core:${fasterxml_version}") implementation("com.fasterxml.jackson.core:jackson-databind:${fasterxml_databind_version}") implementation("com.google.guava:guava:${guava_version}") @@ -31,7 +29,6 @@ dependencies { testImplementation("org.springframework:spring-core:${spring_version}") testImplementation("org.projectlombok:lombok:${lombok_version}") testImplementation("commons-io:commons-io:2.14.0") - testImplementation("io.github.benas:random-beans:${random_beans_version}") testImplementation("org.assertj:assertj-core:${assertj_version}") testImplementation("org.mockito:mockito-core:${mockito_version}") testImplementation("org.xmlunit:xmlunit-legacy:${xmlunit_legacy_version}") diff --git a/sdmx-ml30/build.gradle b/sdmx-ml30/build.gradle index c158fb4..b82c78d 100644 --- a/sdmx-ml30/build.gradle +++ b/sdmx-ml30/build.gradle @@ -23,8 +23,6 @@ dependencies { implementation("org.mapstruct:mapstruct:${mapstruct_version}") annotationProcessor("org.mapstruct:mapstruct-processor:${mapstruct_version}") - implementation("org.apache.commons:commons-collections4:${org_apache_commons_commons_collections4_version}") - implementation("org.apache.commons:commons-lang3:${org_apache_commons_commons_lang3_version}") implementation("com.fasterxml.jackson.core:jackson-core:${fasterxml_version}") implementation("com.fasterxml.jackson.core:jackson-databind:${fasterxml_databind_version}") implementation("com.google.guava:guava:${guava_version}") @@ -35,7 +33,6 @@ dependencies { testImplementation("org.springframework:spring-core:${spring_version}") testImplementation("org.jsonschema2pojo:jsonschema2pojo-core:${jsonschema2pojo_version}") - testImplementation("io.github.benas:random-beans:${random_beans_version}") testImplementation("org.assertj:assertj-core:${assertj_version}") testImplementation("net.javacrumbs.json-unit:json-unit:${json_unit_version}") testImplementation("net.javacrumbs.json-unit:json-unit-assertj:${json_unit_version}") diff --git a/sdmx30-infomodel/build.gradle b/sdmx30-infomodel/build.gradle index c4466b0..033f53e 100644 --- a/sdmx30-infomodel/build.gradle +++ b/sdmx30-infomodel/build.gradle @@ -3,6 +3,4 @@ plugins { } dependencies { - implementation("org.apache.commons:commons-collections4:${org_apache_commons_commons_collections4_version}") - implementation("org.apache.commons:commons-lang3:${org_apache_commons_commons_lang3_version}") } diff --git a/sdmx30-serializer/build.gradle b/sdmx30-serializer/build.gradle index 1e179ec..2e7a7c3 100644 --- a/sdmx30-serializer/build.gradle +++ b/sdmx30-serializer/build.gradle @@ -19,8 +19,6 @@ dependencies { implementation("org.mapstruct:mapstruct:${mapstruct_version}") annotationProcessor("org.mapstruct:mapstruct-processor:${mapstruct_version}") - implementation("org.apache.commons:commons-collections4:${org_apache_commons_commons_collections4_version}") - implementation("org.apache.commons:commons-lang3:${org_apache_commons_commons_lang3_version}") implementation("com.fasterxml.jackson.core:jackson-core:${fasterxml_version}") implementation("com.fasterxml.jackson.core:jackson-databind:${fasterxml_databind_version}") implementation("com.google.guava:guava:${guava_version}") @@ -31,7 +29,6 @@ dependencies { testAnnotationProcessor("org.projectlombok:lombok:${lombok_version}") testImplementation("org.jsonschema2pojo:jsonschema2pojo-core:${jsonschema2pojo_version}") - testImplementation("io.github.benas:random-beans:${random_beans_version}") testImplementation("org.assertj:assertj-core:${assertj_version}") testImplementation("net.javacrumbs.json-unit:json-unit:${json_unit_version}") testImplementation("net.javacrumbs.json-unit:json-unit-assertj:${json_unit_version}") From ea69885a3029fa31c9d5561be9ecee353c849225 Mon Sep 17 00:00:00 2001 From: Ivan Yakubenko Date: Fri, 9 Jan 2026 12:09:49 +0200 Subject: [PATCH 4/4] update README.md --- README.md | 69 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 46c38c7..ad2ddef 100644 --- a/README.md +++ b/README.md @@ -5,20 +5,16 @@ Based on the latest version of the [SDMX 3.0 Specifications](https://sdmx.org/?p statistical data and metadata among international organizations, central banks, and national statistical institutes. ## Packages -- `sdmx30-infomodel` module contains java classes which represent SDMX 3.0 Information Model (Structure Artifacts) such as Data Structure Definitions (DSDs), Metadata Structure Definitions (MSDs), Code Lists, Concept Schemes, and Data and Metadata flows and others. +- `sdmx30-infomodel` module contains java classes which represent SDMX 3.0 Information Model (Structure Artifacts) such as Data Structure Definitions (DSDs), Metadata Structure Definitions (MSDs), Code Lists, Concept Schemes, and Data and Metadata flows and others. +- `sdmx-json10` module providing serialization to JSON 1.0 format for SDMX 2.1 +- `sdmx-json20` module providing serialization to JSON 2.0 format for SDMX 3.0 +- `sdmx-ml21` module providing serialization to ML 2.1 format for SDMX 2.1 +- `sdmx-ml30` module providing serialization to ML 3.0 format for SDMX 3.0 -## Roadmap - -The following modules are currently on project's roadmap for 2023: -- `sdmx30-serialization` module providing (de)serialization to SDMX-JSON, SDMX-ML and SDMX-CSV formats for data and metadata. -- `sdmx30-reporting` module with models describing to Data and Metadata Reporting. -- `sdmx30-client` REST client for SDMX registry. - -Listed above is a subject for extension and other modules might be implemented as well. ## Requirements -- Java JDK 11 and higher +- Java JDK 17 and higher ## Installation @@ -28,11 +24,60 @@ Listed above is a subject for extension and other modules might be implemented a com.epam.jsdmx sdmx30-infomodel - 1.0.0 + 2.0.0 + + +#### Gradle: + compile(group: 'com.epam.jsdmx', name: 'sdmx30-infomodel', version: '2.0.0') + +### sdmx-json10 + +#### Maven: + + com.epam.jsdmx + sdmx-json10 + 2.0.0 + + +#### Gradle: + compile(group: 'com.epam.jsdmx', name: 'sdmx-json10', version: '2.0.0') + +### sdmx-json20 + +#### Maven: + + com.epam.jsdmx + sdmx-json20 + 2.0.0 + + +#### Gradle: + compile(group: 'com.epam.jsdmx', name: 'sdmx-json20', version: '2.0.0') + +### sdmx-ml21 + +#### Maven: + + com.epam.jsdmx + sdmx-ml21 + 2.0.0 + + +#### Gradle: + compile(group: 'com.epam.jsdmx', name: 'sdmx-ml21', version: '2.0.0') + + +### sdmx-ml30 + +#### Maven: + + com.epam.jsdmx + sdmx-ml30 + 2.0.0 #### Gradle: - compile(group: 'com.epam.jsdmx', name: 'sdmx30-infomodel', version: '1.0.0') + compile(group: 'com.epam.jsdmx', name: 'sdmx-ml30', version: '2.0.0') ## License Project is distributed under the Apache License 2.0. See [LICENSE](LICENSE) for more information.