From d77e7b6fcc460961b7d56911e00e46c739cc9f40 Mon Sep 17 00:00:00 2001 From: David Katuscak Date: Fri, 12 Jul 2019 09:08:16 +0200 Subject: [PATCH 01/12] Adds DHIS2 DataValueSet resource type --- .../adapter/dhis/aggregate/DataValueSet.java | 232 ++++++++++++++++++ .../dhis/aggregate/DataValueSetService.java | 43 ++++ .../impl/DataValueSetServiceImpl.java | 91 +++++++ .../adapter/dhis/model/DhisResourceType.java | 7 +- .../fhir/metadata/model/AbstractRule.java | 3 +- .../metadata/model/TransformDataType.java | 4 +- ...0_0_0__Add_New_Resource_Type_Into_Enum.sql | 30 +++ 7 files changed, 407 insertions(+), 3 deletions(-) create mode 100644 dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java create mode 100644 dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSetService.java create mode 100644 dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/impl/DataValueSetServiceImpl.java create mode 100644 fhir/src/main/resources/db/migration/production/V1.1.0.40_0_0__Add_New_Resource_Type_Into_Enum.sql diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java new file mode 100644 index 00000000..b24e152e --- /dev/null +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java @@ -0,0 +1,232 @@ +package org.dhis2.fhir.adapter.dhis.aggregate; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.dhis2.fhir.adapter.dhis.model.DhisResource; +import org.dhis2.fhir.adapter.dhis.model.DhisResourceId; +import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; +import org.dhis2.fhir.adapter.dhis.model.WritableDataValue; + +import javax.annotation.Nonnull; +import java.io.Serializable; +import java.time.ZonedDateTime; +import java.util.List; + +/** + * @author David Katuscak + */ +public class DataValueSet implements DhisResource, Serializable +{ +// reporter > reference -> Organisation unit +// period > start/end -> Period +// group > code > text -> Data element +// group > measurescore -> Data value +// +// orgUnit +// period +// dataElement +// dataValue + + private static final long serialVersionUID = 6347075531883647618L; + + @JsonProperty( access = JsonProperty.Access.WRITE_ONLY ) + private boolean deleted; + + @JsonIgnore + private boolean modified; + + @JsonIgnore + private boolean newResource; + + @JsonIgnore + private boolean local; + + @JsonProperty + @JsonInclude( JsonInclude.Include.NON_NULL ) + private ZonedDateTime lastUpdated; + + @JsonProperty( "dataValueSet" ) + @JsonInclude( JsonInclude.Include.NON_NULL ) + private String id; + + @JsonProperty( "dataSet" ) + private String dataSetId; + + @JsonProperty( "orgUnit" ) + private String orgUnitId; + + @JsonProperty + private String period; + + private List dataValues; + + public DataValueSet() + { + super(); + } + + public DataValueSet( @Nonnull String id ) + { + this.id = id; + } + + public DataValueSet( boolean newResource ) + { + this.newResource = newResource; + this.modified = newResource; + this.local = newResource; + } + + @Override + @JsonIgnore + public String getId() + { + return id; + } + + @Override + public void setId( String id ) + { + this.id = id; + } + + @Override + public DhisResourceId getResourceId() + { + return (getId() == null) ? null : new DhisResourceId( DhisResourceType.DATA_VALUE_SET, getId() ); + } + + @Override + public String getOrgUnitId() + { + return orgUnitId; + } + + public void setOrgUnitId( String orgUnitId ) + { + this.orgUnitId = orgUnitId; + } + + public String getPeriod() + { + return period; + } + + public void setPeriod( String period ) + { + this.period = period; + } + + public String getDataSetId() + { + return dataSetId; + } + + public void setDataSetId( String dataSetId ) + { + this.dataSetId = dataSetId; + } + + @JsonIgnore + @Nonnull + @Override + public DhisResourceType getResourceType() + { + return DhisResourceType.DATA_VALUE_SET; + } + + public List getDataValues() + { + return dataValues; + } + + public void setDataValues( List dataValues ) + { + this.dataValues = dataValues; + } + + @Override + public boolean isNewResource() + { + return newResource; + } + + @Override + public void resetNewResource() + { + this.newResource = false; + this.modified = false; + + if ( lastUpdated == null ) + { + lastUpdated = ZonedDateTime.now(); + } + } + + @Override + public boolean isLocal() + { + return local; + } + + public void setLocal( boolean local ) + { + this.local = local; + } + + public boolean isModified() + { + return modified; + } + + public void setModified( boolean modified ) + { + this.modified = modified; + } + + @Override + public boolean isDeleted() + { + return deleted; + } + + @Override + public ZonedDateTime getLastUpdated() + { + return lastUpdated; + } + + public void setLastUpdated( ZonedDateTime lastUpdated ) + { + this.lastUpdated = lastUpdated; + } +} diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSetService.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSetService.java new file mode 100644 index 00000000..574951f4 --- /dev/null +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSetService.java @@ -0,0 +1,43 @@ +package org.dhis2.fhir.adapter.dhis.aggregate; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import javax.annotation.Nonnull; + +/** + * @author David Katuscak + */ +public interface DataValueSetService +{ + @Nonnull + DataValueSet createOrUpdate( @Nonnull DataValueSet enrollment ); + +// @Nonnull +// DhisResourceResult find( @Nonnull String dataSetId, @Nonnull String orgUnitId, @Nonnull String period, @Nonnull UriFilterApplier uriFilterApplier, int from, int max ); +} diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/impl/DataValueSetServiceImpl.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/impl/DataValueSetServiceImpl.java new file mode 100644 index 00000000..f7c3d02b --- /dev/null +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/impl/DataValueSetServiceImpl.java @@ -0,0 +1,91 @@ +package org.dhis2.fhir.adapter.dhis.aggregate.impl; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.dhis.DhisConflictException; +import org.dhis2.fhir.adapter.dhis.DhisImportUnsuccessfulException; +import org.dhis2.fhir.adapter.dhis.aggregate.DataValueSet; +import org.dhis2.fhir.adapter.dhis.aggregate.DataValueSetService; +import org.dhis2.fhir.adapter.dhis.model.ImportSummaryWebMessage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Nonnull; +import java.util.Objects; + +/** + * @author David Katuscak + */ +@Service +public class DataValueSetServiceImpl implements DataValueSetService +{ + private static final String DATA_VALUE_SETS_URI = "/dataValueSets.json"; + + private final RestTemplate restTemplate; + + @Autowired + public DataValueSetServiceImpl( @Nonnull @Qualifier( "userDhis2RestTemplate" ) RestTemplate restTemplate ) + { + this.restTemplate = restTemplate; + } + + @Nonnull + @Override + public DataValueSet createOrUpdate( @Nonnull final DataValueSet dataValueSet ) + { + final ResponseEntity response; + + try + { + response = restTemplate.postForEntity( DATA_VALUE_SETS_URI, dataValueSet, ImportSummaryWebMessage.class ); + } + catch ( HttpClientErrorException e ) + { + if ( HttpStatus.CONFLICT.equals( e.getStatusCode() ) ) + { + throw new DhisConflictException( "DataValueSet could not be created: " + e.getResponseBodyAsString(), e ); + } + throw e; + } + + final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + + if ( result.isNotSuccessful() ) + { + throw new DhisImportUnsuccessfulException( "Response indicates an unsuccessful DataValueSet import." ); + } + + return dataValueSet; + } +} diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DhisResourceType.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DhisResourceType.java index 78d2be4c..176ace46 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DhisResourceType.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DhisResourceType.java @@ -59,7 +59,12 @@ public enum DhisResourceType /** * Resource is a organisation unit. */ - ORGANIZATION_UNIT( "organisationUnits", "ou" ); + ORGANIZATION_UNIT( "organisationUnits", "ou" ), + + /** + * Resource is a Data Value Set. + */ + DATA_VALUE_SET( "dataValueSets", "dvs" ); private static final Map byTypeName = Arrays.stream( values() ).collect( Collectors.toMap( DhisResourceType::getTypeName, v -> v ) ); diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/AbstractRule.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/AbstractRule.java index 7dcca727..51b0c00f 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/AbstractRule.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/AbstractRule.java @@ -105,7 +105,8 @@ @JsonSubTypes.Type( value = TrackedEntityRule.class, name = "TRACKED_ENTITY" ), @JsonSubTypes.Type( value = ProgramStageRule.class, name = "PROGRAM_STAGE_EVENT" ), @JsonSubTypes.Type( value = OrganizationUnitRule.class, name = "ORGANIZATION_UNIT" ), - @JsonSubTypes.Type( value = EnrollmentRule.class, name = "ENROLLMENT" ) + @JsonSubTypes.Type( value = EnrollmentRule.class, name = "ENROLLMENT" ), + @JsonSubTypes.Type( value = DataValueSetRule.class, name = "DATA_VALUE_SET" ) } ) @JsonFilter( value = AdapterBeanPropertyFilter.FILTER_NAME ) public abstract class AbstractRule extends VersionedBaseMetadata implements Serializable, Comparable, NamedMetadata diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/TransformDataType.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/TransformDataType.java index e8ad0f37..099200f4 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/TransformDataType.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/TransformDataType.java @@ -42,6 +42,7 @@ public enum TransformDataType DHIS_TRACKED_ENTITY_INSTANCE( null ), DHIS_ENROLLMENT( null ), DHIS_EVENT( null ), + DHIS_DATA_VALUE_SET( null ), FHIR_ENCOUNTER( FhirResourceType.ENCOUNTER ), FHIR_LOCATION( FhirResourceType.LOCATION ), FHIR_ORGANIZATION( FhirResourceType.ORGANIZATION ), @@ -54,7 +55,8 @@ public enum TransformDataType FHIR_MEDICATION_REQUEST( FhirResourceType.MEDICATION_REQUEST ), FHIR_PRACTITIONER( FhirResourceType.PRACTITIONER ), FHIR_CARE_PLAN( FhirResourceType.CARE_PLAN ), - FHIR_QUESTIONNAIRE_RESPONSE( FhirResourceType.QUESTIONNAIRE_RESPONSE ); + FHIR_QUESTIONNAIRE_RESPONSE( FhirResourceType.QUESTIONNAIRE_RESPONSE ), + FHIR_MEASURE_REPORT( FhirResourceType.MEASURE_REPORT ); private final FhirResourceType fhirResourceType; diff --git a/fhir/src/main/resources/db/migration/production/V1.1.0.40_0_0__Add_New_Resource_Type_Into_Enum.sql b/fhir/src/main/resources/db/migration/production/V1.1.0.40_0_0__Add_New_Resource_Type_Into_Enum.sql new file mode 100644 index 00000000..067659e3 --- /dev/null +++ b/fhir/src/main/resources/db/migration/production/V1.1.0.40_0_0__Add_New_Resource_Type_Into_Enum.sql @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO PROGRAM_STAGE_EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +-- @formatter:off +INSERT INTO fhir_resource_type_enum VALUES ('MEASURE_REPORT'); \ No newline at end of file From fa3eac3421c7b1c0e634702fdac266b4c0502495 Mon Sep 17 00:00:00 2001 From: David Katuscak Date: Wed, 24 Jul 2019 15:06:19 +0200 Subject: [PATCH 02/12] Add ImportSummariesWebMessage class and adjusts code --- .../dhis/model/ImportSummariesWebMessage.java | 60 +++++++++++++++++++ .../dhis/model/ImportSummaryWebMessage.java | 17 +++--- .../program/impl/EnrollmentServiceImpl.java | 26 ++++---- .../program/impl/EventServiceImpl.java | 32 +++++----- .../impl/TrackedEntityServiceImpl.java | 26 ++++---- 5 files changed, 109 insertions(+), 52 deletions(-) create mode 100644 dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummariesWebMessage.java diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummariesWebMessage.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummariesWebMessage.java new file mode 100644 index 00000000..c678ead1 --- /dev/null +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummariesWebMessage.java @@ -0,0 +1,60 @@ +package org.dhis2.fhir.adapter.dhis.model; + +/* + * Copyright (c) 2004-2018, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * The web message that contains (1 to many) import summaries for creating and updating + * DHIS2 resources. + * + * @author David Katuscak + */ +public class ImportSummariesWebMessage extends WebMessage +{ + private static final long serialVersionUID = -7713823944527785249L; + + private ImportSummaries response; + + public ImportSummaries getResponse() + { + return response; + } + + public void setResponse( ImportSummaries response ) + { + this.response = response; + } + + public boolean isNotSuccessful() + { + return (getStatus() != Status.OK) || + (getResponse().getImportSummaries().size() != 1) || + (getResponse().getImportSummaries().get( 0 ).getStatus() != ImportStatus.SUCCESS) || + (getResponse().getImportSummaries().get( 0 ).getReference() == null); + } +} diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummaryWebMessage.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummaryWebMessage.java index 834e09c0..69d18af9 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummaryWebMessage.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummaryWebMessage.java @@ -1,7 +1,7 @@ package org.dhis2.fhir.adapter.dhis.model; /* - * Copyright (c) 2004-2018, University of Oslo + * Copyright (c) 2004-2019, University of Oslo * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,32 +29,29 @@ */ /** - * The web message that contains import summaries for creating and updating + * The web message that contains (1) import summary for creating and updating * DHIS2 resources. * * @author volsch */ -public class ImportSummaryWebMessage extends WebMessage +public class ImportSummaryWebMessage extends WebMessage { private static final long serialVersionUID = -7713823944527785249L; - private ImportSummaries response; + private ImportSummary response; - public ImportSummaries getResponse() + public ImportSummary getResponse() { return response; } - public void setResponse( ImportSummaries response ) + public void setResponse( ImportSummary response ) { this.response = response; } public boolean isNotSuccessful() { - return (getStatus() != Status.OK) || - (getResponse().getImportSummaries().size() != 1) || - (getResponse().getImportSummaries().get( 0 ).getStatus() != ImportStatus.SUCCESS) || - (getResponse().getImportSummaries().get( 0 ).getReference() == null); + return getStatus() != Status.OK; } } diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EnrollmentServiceImpl.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EnrollmentServiceImpl.java index b7c2977a..43a34c23 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EnrollmentServiceImpl.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EnrollmentServiceImpl.java @@ -41,8 +41,8 @@ import org.dhis2.fhir.adapter.dhis.model.DhisResourceComparator; import org.dhis2.fhir.adapter.dhis.model.ImportStatus; import org.dhis2.fhir.adapter.dhis.model.ImportSummaries; +import org.dhis2.fhir.adapter.dhis.model.ImportSummariesWebMessage; import org.dhis2.fhir.adapter.dhis.model.ImportSummary; -import org.dhis2.fhir.adapter.dhis.model.ImportSummaryWebMessage; import org.dhis2.fhir.adapter.dhis.model.Status; import org.dhis2.fhir.adapter.dhis.tracker.program.Enrollment; import org.dhis2.fhir.adapter.dhis.tracker.program.EnrollmentService; @@ -207,7 +207,7 @@ public Enrollment createOrUpdate( @Nonnull Enrollment enrollment ) @Nonnull protected Enrollment _create( @Nonnull Enrollment enrollment ) { - final ResponseEntity response; + final ResponseEntity response; if ( enrollment.getId() == null ) { @@ -230,7 +230,7 @@ protected Enrollment _create( @Nonnull Enrollment enrollment ) try { response = restTemplate.exchange( ENROLLMENT_CREATE_URI, HttpMethod.PUT, new HttpEntity<>( enrollment ), - ImportSummaryWebMessage.class, enrollment.getId() ); + ImportSummariesWebMessage.class, enrollment.getId() ); } catch ( HttpClientErrorException e ) { @@ -242,7 +242,7 @@ protected Enrollment _create( @Nonnull Enrollment enrollment ) throw e; } - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); if ( result.isNotSuccessful() ) { @@ -283,11 +283,11 @@ protected Enrollment _update( @Nonnull Enrollment enrollment ) // update of included events is not supported enrollment.setEvents( Collections.emptyList() ); - final ResponseEntity response; + final ResponseEntity response; try { response = restTemplate.exchange( ENROLLMENT_UPDATE_URI, HttpMethod.PUT, new HttpEntity<>( enrollment ), - ImportSummaryWebMessage.class, enrollment.getId() ); + ImportSummariesWebMessage.class, enrollment.getId() ); } catch ( HttpClientErrorException e ) { @@ -299,7 +299,7 @@ protected Enrollment _update( @Nonnull Enrollment enrollment ) throw e; } - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); if ( result.getStatus() != Status.OK ) { @@ -327,10 +327,10 @@ public void persistSave( @Nonnull Collection resources, boolean crea final List enrollments = resources.stream().sorted( DhisResourceComparator.INSTANCE ).collect( Collectors.toList() ); enrollments.forEach( e -> e.setEvents( Collections.emptyList() ) ); - final ResponseEntity response = - restTemplate.postForEntity( create ? ENROLLMENT_CREATES_URI : ENROLLMENT_UPDATES_URI, new DhisEnrollments( enrollments ), ImportSummaryWebMessage.class ); + final ResponseEntity response = + restTemplate.postForEntity( create ? ENROLLMENT_CREATES_URI : ENROLLMENT_UPDATES_URI, new DhisEnrollments( enrollments ), ImportSummariesWebMessage.class ); - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); final int size = enrollments.size(); if ( result.getStatus() != Status.OK || result.getResponse() == null || result.getResponse().getImportSummaries().size() != size ) @@ -406,10 +406,10 @@ public void persistDeleteById( @Nonnull Collection ids, @Nullable Consum } final List Enrollments = ids.stream().map( Enrollment::new ).sorted( DhisResourceComparator.INSTANCE ).collect( Collectors.toList() ); - final ResponseEntity response = - restTemplate.postForEntity( ENROLLMENT_DELETES_URI, new DhisEnrollments( Enrollments ), ImportSummaryWebMessage.class ); + final ResponseEntity response = + restTemplate.postForEntity( ENROLLMENT_DELETES_URI, new DhisEnrollments( Enrollments ), ImportSummariesWebMessage.class ); - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); final int size = Enrollments.size(); if ( result.getStatus() != Status.OK || result.getResponse() == null || result.getResponse().getImportSummaries().size() != size ) diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EventServiceImpl.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EventServiceImpl.java index b1f6bea6..6d7e7279 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EventServiceImpl.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EventServiceImpl.java @@ -46,8 +46,8 @@ import org.dhis2.fhir.adapter.dhis.model.DhisResourceComparator; import org.dhis2.fhir.adapter.dhis.model.DhisResourceResult; import org.dhis2.fhir.adapter.dhis.model.ImportStatus; +import org.dhis2.fhir.adapter.dhis.model.ImportSummariesWebMessage; import org.dhis2.fhir.adapter.dhis.model.ImportSummary; -import org.dhis2.fhir.adapter.dhis.model.ImportSummaryWebMessage; import org.dhis2.fhir.adapter.dhis.model.Status; import org.dhis2.fhir.adapter.dhis.model.UriFilterApplier; import org.dhis2.fhir.adapter.dhis.tracker.program.Event; @@ -173,10 +173,10 @@ public void persistDeleteById( @Nonnull Collection ids, @Nullable Consum } final List Events = ids.stream().map( Event::new ).sorted( DhisResourceComparator.INSTANCE ).collect( Collectors.toList() ); - final ResponseEntity response = - restTemplate.postForEntity( DELETES_URI, new DhisEvents( Events ), ImportSummaryWebMessage.class ); + final ResponseEntity response = + restTemplate.postForEntity( DELETES_URI, new DhisEvents( Events ), ImportSummariesWebMessage.class ); - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); final int size = Events.size(); if ( result.getStatus() != Status.OK || result.getResponse() == null || result.getResponse().getImportSummaries().size() != size ) @@ -241,10 +241,10 @@ public void persistSave( @Nonnull Collection resources, boolean create, @ } final List events = resources.stream().sorted( DhisResourceComparator.INSTANCE ).collect( Collectors.toList() ); - final ResponseEntity response = - restTemplate.postForEntity( create ? CREATES_URI : UPDATES_URI, new DhisEvents( events ), ImportSummaryWebMessage.class ); + final ResponseEntity response = + restTemplate.postForEntity( create ? CREATES_URI : UPDATES_URI, new DhisEvents( events ), ImportSummariesWebMessage.class ); - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); final int size = events.size(); if ( result.getStatus() != Status.OK || result.getResponse() == null || result.getResponse().getImportSummaries().size() != size ) @@ -373,7 +373,7 @@ public Instant poll( @Nonnull DhisSyncGroup group, @Nonnull Instant lastUpdated, @Nonnull protected Event create( @Nonnull Event event ) { - final ResponseEntity response; + final ResponseEntity response; if ( event.getId() == null ) { @@ -383,7 +383,7 @@ protected Event create( @Nonnull Event event ) try { response = restTemplate.exchange( CREATE_URI, HttpMethod.PUT, new HttpEntity<>( event ), - ImportSummaryWebMessage.class, event.getId() ); + ImportSummariesWebMessage.class, event.getId() ); } catch ( HttpClientErrorException e ) { @@ -395,7 +395,7 @@ protected Event create( @Nonnull Event event ) throw e; } - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); if ( result.isNotSuccessful() ) { @@ -412,12 +412,12 @@ protected Event create( @Nonnull Event event ) @Nonnull protected Event update( @Nonnull Event event ) { - final ResponseEntity response; + final ResponseEntity response; try { response = restTemplate.exchange( UPDATE_URI, HttpMethod.PUT, new HttpEntity<>( event ), - ImportSummaryWebMessage.class, event.getId() ); + ImportSummariesWebMessage.class, event.getId() ); } catch ( HttpClientErrorException e ) { @@ -429,7 +429,7 @@ protected Event update( @Nonnull Event event ) throw e; } - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); if ( result.getStatus() != Status.OK ) { @@ -474,11 +474,11 @@ public DhisResourceResult find( @Nonnull String programId, @Nonnull Strin protected void update( @Nonnull MinimalEvent event ) { - final ResponseEntity response; + final ResponseEntity response; try { response = restTemplate.exchange( UPDATE_DATA_VALUE_URI, HttpMethod.PUT, new HttpEntity<>( event ), - ImportSummaryWebMessage.class, event.getId(), event.getDataElementId() ); + ImportSummariesWebMessage.class, event.getId(), event.getDataElementId() ); } catch ( HttpClientErrorException e ) { @@ -488,7 +488,7 @@ protected void update( @Nonnull MinimalEvent event ) } throw e; } - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); if ( result.getStatus() != Status.OK ) { diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/impl/TrackedEntityServiceImpl.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/impl/TrackedEntityServiceImpl.java index 184d2674..badb13c9 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/impl/TrackedEntityServiceImpl.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/impl/TrackedEntityServiceImpl.java @@ -47,8 +47,8 @@ import org.dhis2.fhir.adapter.dhis.model.DhisResourceResult; import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; import org.dhis2.fhir.adapter.dhis.model.ImportStatus; +import org.dhis2.fhir.adapter.dhis.model.ImportSummariesWebMessage; import org.dhis2.fhir.adapter.dhis.model.ImportSummary; -import org.dhis2.fhir.adapter.dhis.model.ImportSummaryWebMessage; import org.dhis2.fhir.adapter.dhis.model.Status; import org.dhis2.fhir.adapter.dhis.model.UriFilterApplier; import org.dhis2.fhir.adapter.dhis.sync.DhisLastUpdated; @@ -293,10 +293,10 @@ public void persistSave( @Nonnull Collection resources, b trackedEntityInstances.forEach( this::clear ); - final ResponseEntity response = - restTemplate.postForEntity( create ? CREATES_URI : UPDATES_URI, new TrackedEntityInstances( trackedEntityInstances ), ImportSummaryWebMessage.class ); + final ResponseEntity response = + restTemplate.postForEntity( create ? CREATES_URI : UPDATES_URI, new TrackedEntityInstances( trackedEntityInstances ), ImportSummariesWebMessage.class ); - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); final int size = trackedEntityInstances.size(); if ( result.getStatus() != Status.OK || result.getResponse() == null || result.getResponse().getImportSummaries().size() != size ) @@ -375,10 +375,10 @@ public void persistDeleteById( @Nonnull Collection ids, @Nullable Consum } final List trackedEntityInstances = ids.stream().map( TrackedEntityInstance::new ).sorted( DhisResourceComparator.INSTANCE ).collect( Collectors.toList() ); - final ResponseEntity response = - restTemplate.postForEntity( DELETES_URI, new TrackedEntityInstances( trackedEntityInstances ), ImportSummaryWebMessage.class ); + final ResponseEntity response = + restTemplate.postForEntity( DELETES_URI, new TrackedEntityInstances( trackedEntityInstances ), ImportSummariesWebMessage.class ); - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); final int size = trackedEntityInstances.size(); if ( result.getStatus() != Status.OK || result.getResponse() == null || result.getResponse().getImportSummaries().size() != size ) @@ -457,7 +457,7 @@ protected TrackedEntityInstance create( @Nonnull TrackedEntityInstance trackedEn { final DhisSyncGroup syncGroup = storedItemService.findSyncGroupById( DhisSyncGroup.DEFAULT_ID ) .orElseThrow( () -> new DhisResourceException( "Could not load default DHIS2 sync group." ) ); - final ResponseEntity response; + final ResponseEntity response; if ( trackedEntityInstance.getId() == null ) { @@ -467,7 +467,7 @@ protected TrackedEntityInstance create( @Nonnull TrackedEntityInstance trackedEn try { clear( trackedEntityInstance ); - response = restTemplate.postForEntity( CREATE_URI, trackedEntityInstance, ImportSummaryWebMessage.class, trackedEntityInstance.getId() ); + response = restTemplate.postForEntity( CREATE_URI, trackedEntityInstance, ImportSummariesWebMessage.class, trackedEntityInstance.getId() ); } catch ( HttpClientErrorException e ) { @@ -479,7 +479,7 @@ protected TrackedEntityInstance create( @Nonnull TrackedEntityInstance trackedEn throw e; } - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); if ( result.isNotSuccessful() ) { @@ -500,12 +500,12 @@ protected TrackedEntityInstance update( @Nonnull TrackedEntityInstance trackedEn final DhisSyncGroup syncGroup = storedItemService.findSyncGroupById( DhisSyncGroup.DEFAULT_ID ) .orElseThrow( () -> new DhisResourceException( "Could not load default DHIS2 sync group." ) ); - final ResponseEntity response; + final ResponseEntity response; try { clear( trackedEntityInstance ); response = restTemplate.exchange( UPDATE_URI, HttpMethod.PUT, new HttpEntity<>( trackedEntityInstance ), - ImportSummaryWebMessage.class, trackedEntityInstance.getId() ); + ImportSummariesWebMessage.class, trackedEntityInstance.getId() ); } catch ( HttpClientErrorException e ) { @@ -515,7 +515,7 @@ protected TrackedEntityInstance update( @Nonnull TrackedEntityInstance trackedEn } throw e; } - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); if ( result.getStatus() != Status.OK ) { throw new DhisImportUnsuccessfulException( "Response indicates an unsuccessful import of tracked entity instance: " + result.getStatus() ); From 404554c12617731a42e199dd892a8ea31c5108db Mon Sep 17 00:00:00 2001 From: David Katuscak Date: Wed, 24 Jul 2019 15:07:23 +0200 Subject: [PATCH 03/12] WIP implementation of MeasureReport -> DataValueSets tranformation --- .../adapter/dhis/aggregate/DataValueSet.java | 71 +++- .../dhis/aggregate/DataValueSetService.java | 3 - .../fhir/adapter/dhis/model/DataElements.java | 127 +++++++ .../sync/impl/DhisResourceRepositoryImpl.java | 65 +++- .../Dstu3MeasureReportResourceProvider.java | 80 +++++ .../r4/R4MeasureReportResourceProvider.java | 80 +++++ .../DataValueSetRuleEventListener.java | 42 +++ ...reCreateSaveDataValueSetRuleValidator.java | 61 ++++ .../scripted/ScriptedDataValueSet.java | 53 +++ .../WritableScriptedDataValueSet.java | 319 ++++++++++++++++++ 10 files changed, 882 insertions(+), 19 deletions(-) create mode 100644 dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataElements.java create mode 100644 fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java create mode 100644 fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/listener/DataValueSetRuleEventListener.java create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveDataValueSetRuleValidator.java create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/ScriptedDataValueSet.java create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/WritableScriptedDataValueSet.java diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java index b24e152e..5d22a0e7 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java @@ -31,6 +31,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import org.dhis2.fhir.adapter.dhis.model.DataValue; import org.dhis2.fhir.adapter.dhis.model.DhisResource; import org.dhis2.fhir.adapter.dhis.model.DhisResourceId; import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; @@ -39,7 +40,9 @@ import javax.annotation.Nonnull; import java.io.Serializable; import java.time.ZonedDateTime; +import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * @author David Katuscak @@ -104,6 +107,7 @@ public DataValueSet( boolean newResource ) this.newResource = newResource; this.modified = newResource; this.local = newResource; + this.dataValues = new ArrayList<>(); } @Override @@ -164,16 +168,6 @@ public DhisResourceType getResourceType() return DhisResourceType.DATA_VALUE_SET; } - public List getDataValues() - { - return dataValues; - } - - public void setDataValues( List dataValues ) - { - this.dataValues = dataValues; - } - @Override public boolean isNewResource() { @@ -229,4 +223,61 @@ public void setLastUpdated( ZonedDateTime lastUpdated ) { this.lastUpdated = lastUpdated; } + + public List getDataValues() + { + return dataValues; + } + + public void setDataValues( List dataValues ) + { + this.dataValues = dataValues; + } + + public boolean containsDataValue( @Nonnull String dataElementId ) + { + return getDataValues().stream().anyMatch( dv -> Objects.equals( dataElementId, dv.getDataElementId() ) ); + } + + public boolean containsDataValue( @Nonnull String dataElementId, @Nonnull String value ) + { + return getDataValues().stream() + .anyMatch( dv -> Objects.equals( dataElementId, dv.getDataElementId() ) + && dv.getValue() != null + && Objects.equals( value, String.valueOf( dv.getValue() ) ) ); + } + + public boolean containsDataValueWithValue( @Nonnull String dataElementId ) + { + return getDataValues().stream() + .filter( dv -> ( dv.getValue() != null ) ) + .anyMatch( dv -> Objects.equals( dataElementId, dv.getDataElementId() ) ); + } + + @Nonnull + public WritableDataValue getDataValue( @Nonnull String dataElementId ) + { + if ( getDataValues() == null ) + { + setDataValues( new ArrayList<>() ); + } + + WritableDataValue dataValue = getDataValues().stream() + .filter( dv -> Objects.equals( dataElementId, dv.getDataElementId() ) ) + .findFirst() + .orElse( null ); + + if ( dataValue == null ) + { + dataValue = new WritableDataValue( dataElementId, true ); + getDataValues().add( dataValue ); + } + return dataValue; + } + + @JsonIgnore + public boolean isAnyDataValueModified() + { + return (getDataValues() != null) && getDataValues().stream().anyMatch( DataValue::isModified ); + } } diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSetService.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSetService.java index 574951f4..30c32d3b 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSetService.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSetService.java @@ -37,7 +37,4 @@ public interface DataValueSetService { @Nonnull DataValueSet createOrUpdate( @Nonnull DataValueSet enrollment ); - -// @Nonnull -// DhisResourceResult find( @Nonnull String dataSetId, @Nonnull String orgUnitId, @Nonnull String period, @Nonnull UriFilterApplier uriFilterApplier, int from, int max ); } diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataElements.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataElements.java new file mode 100644 index 00000000..0366f269 --- /dev/null +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataElements.java @@ -0,0 +1,127 @@ +package org.dhis2.fhir.adapter.dhis.model; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.commons.lang3.StringUtils; + +import javax.annotation.Nonnull; +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * @author David Katuscak + */ +public class DataElements implements Serializable +{ + private static final long serialVersionUID = -4563360527610569923L; + + @JsonProperty( "dataElements" ) + private Collection dataElements; + + @JsonIgnore + private transient volatile Map dataElementsById; + + @JsonIgnore + private transient volatile Map dataElementsByName; + + @JsonIgnore + private transient volatile Map dataElementsByCode; + + public DataElements() + { + this.dataElements = Collections.emptyList(); + } + + public DataElements( @Nonnull Collection dataElements ) + { + this.dataElements = dataElements; + } + + @Nonnull + public Optional getOptional( @Nonnull Reference reference ) + { + switch ( reference.getType() ) + { + case CODE: + return getOptionalByCode( reference.getValue() ); + case NAME: + return getOptionalByName( reference.getValue() ); + case ID: + return getOptionalById( reference.getValue() ); + default: + throw new AssertionError( "Unhandled reference type: " + reference.getType() ); + } + } + + @Nonnull + public Optional getOptionalById( @Nonnull String id ) + { + Map tempDataElementsById = dataElementsById; + if ( tempDataElementsById == null ) + { + dataElementsById = tempDataElementsById = dataElements.stream() + .map( ImmutableDataElement::new ) + .collect( Collectors.toMap( DataElement::getId, de -> de ) ); + } + return Optional.ofNullable( tempDataElementsById.get( id ) ); + } + + @Nonnull + public Optional getOptionalByCode( @Nonnull String code ) + { + Map tempDataElementsByCode = dataElementsByCode; + if ( tempDataElementsByCode == null ) + { + dataElementsByCode = tempDataElementsByCode = dataElements.stream() + .filter( de -> StringUtils.isNotBlank( de.getCode() ) ) + .map( ImmutableDataElement::new ) + .collect( Collectors.toMap( DataElement::getCode, de -> de ) ); + } + return Optional.ofNullable( tempDataElementsByCode.get( code ) ); + } + + @Nonnull + public Optional getOptionalByName( @Nonnull String name ) + { + Map tempDataElementsByName = dataElementsByName; + if ( tempDataElementsByName == null ) + { + dataElementsByName = tempDataElementsByName = dataElements.stream() + .map( ImmutableDataElement::new ) + .collect( Collectors.toMap( DataElement::getName, de -> de ) ); + } + return Optional.ofNullable( tempDataElementsByName.get( name ) ); + } +} diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/sync/impl/DhisResourceRepositoryImpl.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/sync/impl/DhisResourceRepositoryImpl.java index b77cdeaa..2111a55d 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/sync/impl/DhisResourceRepositoryImpl.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/sync/impl/DhisResourceRepositoryImpl.java @@ -28,6 +28,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import org.dhis2.fhir.adapter.dhis.aggregate.DataValueSet; +import org.dhis2.fhir.adapter.dhis.aggregate.DataValueSetService; import org.dhis2.fhir.adapter.dhis.model.DhisResource; import org.dhis2.fhir.adapter.dhis.model.DhisResourceId; import org.dhis2.fhir.adapter.dhis.model.Reference; @@ -54,6 +56,7 @@ * * @author volsch * @author Charles Chigoriwa (ITINORDIC) + * @author David Katuscak */ @Component public class DhisResourceRepositoryImpl implements DhisResourceRepository @@ -68,13 +71,17 @@ public class DhisResourceRepositoryImpl implements DhisResourceRepository private final EventService eventService; + private final DataValueSetService dataValueSetService; + public DhisResourceRepositoryImpl( @Nonnull OrganizationUnitService organizationUnitService, - @Nonnull TrackedEntityService trackedEntityService, @Nonnull EnrollmentService enrollmentService, @Nonnull EventService eventService ) + @Nonnull TrackedEntityService trackedEntityService, @Nonnull EnrollmentService enrollmentService, + @Nonnull EventService eventService, @Nonnull DataValueSetService dataValueSetService ) { this.organizationUnitService = organizationUnitService; this.trackedEntityService = trackedEntityService; this.enrollmentService = enrollmentService; this.eventService = eventService; + this.dataValueSetService = dataValueSetService; } @Nonnull @@ -91,8 +98,10 @@ public Optional findRefreshed( @Nonnull DhisResourceId d return eventService.findOneById( dhisResourceId.getId() ); case ENROLLMENT: return enrollmentService.findOneById( dhisResourceId.getId() ); + case DATA_VALUE_SET: + throw new UnsupportedOperationException( "Finding DHIS2 DataValueSet resources is not supported." ); default: - throw new AssertionError( "Unhandled DHIS resource type: " + dhisResourceId.getType() ); + throw new AssertionError( "Unhandled DHIS2 resource type: " + dhisResourceId.getType() ); } } @@ -107,9 +116,10 @@ public Optional findRefreshedDeleted( @Nonnull DhisResou case ORGANIZATION_UNIT: case TRACKED_ENTITY: case ENROLLMENT: - throw new UnsupportedOperationException( "Retrieving deleted " + dhisResourceId.getType() + " DHIS resource items is not supported." ); + case DATA_VALUE_SET: + throw new UnsupportedOperationException( "Retrieving deleted " + dhisResourceId.getType() + " DHIS2 resource items is not supported." ); default: - throw new AssertionError( "Unhandled DHIS resource type: " + dhisResourceId.getType() ); + throw new AssertionError( "Unhandled DHIS2 resource type: " + dhisResourceId.getType() ); } } @@ -136,8 +146,11 @@ public DhisResource save( @Nonnull DhisResource resource ) case PROGRAM_STAGE_EVENT: saveEvent( (Event) resource ); break; + case DATA_VALUE_SET: + saveDataValueSet( (DataValueSet) resource ); + break; default: - throw new AssertionError( "Unhandled DHIS resource type: " + resource.getResourceType() ); + throw new AssertionError( "Unhandled DHIS2 resource type: " + resource.getResourceType() ); } return resource; } @@ -153,8 +166,10 @@ public boolean delete( @Nonnull DhisResource resource ) return enrollmentService.delete( resource.getId() ); case PROGRAM_STAGE_EVENT: return eventService.delete( resource.getId() ); + case DATA_VALUE_SET: + throw new UnsupportedOperationException( "Deleting DHIS2 DataValueSet resources is nut supported." ); default: - throw new AssertionError( "Unhandled DHIS resource type: " + resource.getResourceType() ); + throw new AssertionError( "Unhandled DHIS2 resource type: " + resource.getResourceType() ); } } @@ -248,4 +263,42 @@ else if ( enrollment.isModified() ) return updated; } + + private boolean saveDataValueSet( @Nonnull DataValueSet dataValueSet ) + { + if ( validateDataValueSet( dataValueSet ) ) + { + if ( dataValueSet.isNewResource() ) + { + logger.info( "Creating new DataValueSet." ); + dataValueSetService.createOrUpdate( dataValueSet ); + logger.info( "Created new DataValueSet for dataSetId: {}, orgUnit: {}, period: {}.", + dataValueSet.getDataSetId(), dataValueSet.getOrgUnitId(), dataValueSet.getPeriod() ); + return true; + } + else if ( dataValueSet.isModified() ) + { + logger.info( "Updating existing DataValueSet." ); + dataValueSetService.createOrUpdate( dataValueSet ); + logger.info( "Created new DataValueSet for dataSetId: {}, orgUnit: {}, period: {}.", + dataValueSet.getDataSetId(), dataValueSet.getOrgUnitId(), dataValueSet.getPeriod() ); + return true; + } + } + + return false; + } + + private boolean validateDataValueSet( @Nonnull DataValueSet dataValueSet ) + { + if ( dataValueSet.getDataSetId() != null && !dataValueSet.getDataSetId().isEmpty() && + dataValueSet.getOrgUnitId() != null && !dataValueSet.getOrgUnitId().isEmpty() && + dataValueSet.getPeriod() != null && !dataValueSet.getPeriod().isEmpty() && + dataValueSet.getDataValues() != null && !dataValueSet.getDataValues().isEmpty() ) + { + return true; + } + + return false; + } } diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java new file mode 100644 index 00000000..6547ae0e --- /dev/null +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java @@ -0,0 +1,80 @@ +package org.dhis2.fhir.adapter.fhir.server.provider.dstu3; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import ca.uhn.fhir.rest.annotation.Count; +import ca.uhn.fhir.rest.annotation.OptionalParam; +import ca.uhn.fhir.rest.annotation.RawParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.param.DateRangeParam; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirClientResourceRepository; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirClientSystemRepository; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.repository.DhisRepository; +import org.dhis2.fhir.adapter.fhir.repository.FhirRepository; +import org.dhis2.fhir.adapter.fhir.server.provider.AbstractReadOnlyResourceProvider; +import org.hl7.fhir.dstu3.model.MeasureReport; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; + +/** + * DSTU3 resource provider + * + * @author David Katuscak + */ +@Component +public class Dstu3MeasureReportResourceProvider extends AbstractReadOnlyResourceProvider +{ + public Dstu3MeasureReportResourceProvider( @Nonnull FhirClientResourceRepository fhirClientResourceRepository, + @Nonnull FhirClientSystemRepository fhirClientSystemRepository, + @Nonnull FhirRepository fhirRepository, @Nonnull DhisRepository dhisRepository ) + { + super( MeasureReport.class, fhirClientResourceRepository, fhirClientSystemRepository, fhirRepository, dhisRepository ); + } + + @Nonnull + @Override + public FhirVersion getFhirVersion() + { + return FhirVersion.DSTU3; + } + + @Search( allowUnknownParams = true ) + @Nonnull + public IBundleProvider search( @Nonnull RequestDetails requestDetails, @Nullable @Count Integer count, @Nullable @OptionalParam( name = SP_LAST_UPDATED ) DateRangeParam lastUpdatedDateRange, @Nullable @RawParam Map> filter ) + { + return search( requestDetails, count, null, lastUpdatedDateRange, filter ); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java new file mode 100644 index 00000000..95edc6b4 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java @@ -0,0 +1,80 @@ +package org.dhis2.fhir.adapter.fhir.server.provider.r4; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import ca.uhn.fhir.rest.annotation.Count; +import ca.uhn.fhir.rest.annotation.OptionalParam; +import ca.uhn.fhir.rest.annotation.RawParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.param.DateRangeParam; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirClientResourceRepository; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirClientSystemRepository; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.repository.DhisRepository; +import org.dhis2.fhir.adapter.fhir.repository.FhirRepository; +import org.dhis2.fhir.adapter.fhir.server.provider.AbstractReadOnlyResourceProvider; +import org.hl7.fhir.r4.model.MeasureReport; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; + +/** + * r4 resource provider + * + * @author David Katuscak + */ +@Component +public class R4MeasureReportResourceProvider extends AbstractReadOnlyResourceProvider +{ + public R4MeasureReportResourceProvider( @Nonnull FhirClientResourceRepository fhirClientResourceRepository, + @Nonnull FhirClientSystemRepository fhirClientSystemRepository, + @Nonnull FhirRepository fhirRepository, @Nonnull DhisRepository dhisRepository ) + { + super( MeasureReport.class, fhirClientResourceRepository, fhirClientSystemRepository, fhirRepository, dhisRepository ); + } + + @Nonnull + @Override + public FhirVersion getFhirVersion() + { + return FhirVersion.R4; + } + + @Search( allowUnknownParams = true ) + @Nonnull + public IBundleProvider search( @Nonnull RequestDetails requestDetails, @Nullable @Count Integer count, @Nullable @OptionalParam( name = SP_LAST_UPDATED ) DateRangeParam lastUpdatedDateRange, @Nullable @RawParam Map> filter ) + { + return search( requestDetails, count, null, lastUpdatedDateRange, filter ); + } +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/listener/DataValueSetRuleEventListener.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/listener/DataValueSetRuleEventListener.java new file mode 100644 index 00000000..3e7e600d --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/listener/DataValueSetRuleEventListener.java @@ -0,0 +1,42 @@ +package org.dhis2.fhir.adapter.fhir.metadata.repository.listener; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.fhir.metadata.model.DataValueSetRule; +import org.springframework.stereotype.Component; + +/** + * Event listener that prepares {@link DataValueSetRule} class before saving. + * + * @author David Katuscak + */ +@Component +public class DataValueSetRuleEventListener extends AbstractRuleEventListener +{ +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveDataValueSetRuleValidator.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveDataValueSetRuleValidator.java new file mode 100644 index 00000000..4b9c5dc5 --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveDataValueSetRuleValidator.java @@ -0,0 +1,61 @@ +package org.dhis2.fhir.adapter.fhir.metadata.repository.validator; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.fhir.metadata.model.DataValueSetRule; +import org.dhis2.fhir.adapter.fhir.metadata.model.TransformDataType; +import org.springframework.stereotype.Component; +import org.springframework.validation.Errors; + +import javax.annotation.Nonnull; +import javax.persistence.EntityManager; + +/** + * Spring Data REST validator for {@link DataValueSetRule}. + * + * @author David Katuscak + */ +@Component +public class BeforeCreateSaveDataValueSetRuleValidator extends AbstractBeforeCreateSaveRuleValidator + implements MetadataValidator +{ + public BeforeCreateSaveDataValueSetRuleValidator( @Nonnull EntityManager entityManager ) + { + super( DataValueSetRule.class, entityManager ); + } + + @Override protected void doValidate( @Nonnull DataValueSetRule rule, @Nonnull Errors errors ) + { + validate( rule, TransformDataType.DHIS_DATA_VALUE_SET, errors ); + + //TODO: Do I need to validate some script? E.g. as in Enrollment validator? + BeforeCreateSaveFhirResourceMappingValidator.checkValidOrgLookupScript( errors, "DataValueSetRule.", "orgUnitLookupScript", rule.getFhirResourceType(), rule.getOrgUnitLookupScript() ); + BeforeCreateSaveFhirResourceMappingValidator.checkValidLocationLookupScript( errors, "DataValueSetRule.", "locationLookupScript", rule.getFhirResourceType(), rule.getLocationLookupScript() ); + } +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/ScriptedDataValueSet.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/ScriptedDataValueSet.java new file mode 100644 index 00000000..799cb863 --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/ScriptedDataValueSet.java @@ -0,0 +1,53 @@ +package org.dhis2.fhir.adapter.fhir.transform.scripted; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.dhis.model.WritableDataValue; +import org.dhis2.fhir.adapter.scriptable.Scriptable; + +import javax.annotation.Nonnull; +import java.util.List; + +/** + * Mutable or immutable data value set resource that can be used by scripts safely. + * + * @author David Katuscak + */ +@Scriptable +public interface ScriptedDataValueSet extends ScriptedDhisResource +{ + @Nonnull + String getDataSetId(); + + @Nonnull + String getPeriod(); + + @Nonnull + List getDataValues(); +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/WritableScriptedDataValueSet.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/WritableScriptedDataValueSet.java new file mode 100644 index 00000000..42ed9346 --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/WritableScriptedDataValueSet.java @@ -0,0 +1,319 @@ +package org.dhis2.fhir.adapter.fhir.transform.scripted; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.converter.ConversionException; +import org.dhis2.fhir.adapter.dhis.aggregate.DataValueSet; +import org.dhis2.fhir.adapter.dhis.converter.ValueConverter; +import org.dhis2.fhir.adapter.dhis.model.DataElement; +import org.dhis2.fhir.adapter.dhis.model.DataElements; +import org.dhis2.fhir.adapter.dhis.model.DataValue; +import org.dhis2.fhir.adapter.dhis.model.DhisResourceId; +import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; +import org.dhis2.fhir.adapter.dhis.model.Reference; +import org.dhis2.fhir.adapter.dhis.model.WritableDataValue; +import org.dhis2.fhir.adapter.dhis.orgunit.OrganizationUnitService; +import org.dhis2.fhir.adapter.dhis.tracker.trackedentity.TrackedEntityAttribute; +import org.dhis2.fhir.adapter.dhis.tracker.trackedentity.TrackedEntityAttributeValue; +import org.dhis2.fhir.adapter.fhir.transform.TransformerException; +import org.dhis2.fhir.adapter.fhir.transform.TransformerMappingException; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.ScriptedDateTimeUtils; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.Serializable; +import java.time.ZonedDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +/** + * Mutable data value set resource that can be used by scripts safely. + * + * @author David Katuscak + */ +@Scriptable +@ScriptType( value = "DataValueSet", var = "dataValueSet", transformDataType = "DHIS_DATA_VALUE_SET", + description = "Data Value Set. If Data Value Set is not new and will be modified, it will be persisted." ) +public class WritableScriptedDataValueSet implements ScriptedDataValueSet, Serializable +{ + private final DataElements dataElements; + + private final DataValueSet dataValueSet; + + private final OrganizationUnitService organizationUnitService; + + private final ValueConverter valueConverter; + + public WritableScriptedDataValueSet ( @Nonnull DataElements dataElements, @Nonnull DataValueSet dataValueSet, + @Nonnull OrganizationUnitService organizationUnitService, @Nonnull ValueConverter valueConverter ) + { + this.dataElements = dataElements; + this.dataValueSet = dataValueSet; + this.organizationUnitService = organizationUnitService; + this.valueConverter = valueConverter; + } + + @Nullable + @Override + @ScriptMethod( description = "Returns the ID of the DataValueSet on DHIS2. Return null if the instance is new." ) + public String getId() + { + return dataValueSet.getId(); + } + + @Nonnull + @Override + public DhisResourceType getResourceType() + { + return dataValueSet.getResourceType(); + } + + @Nullable + @Override + public DhisResourceId getResourceId() + { + return dataValueSet.getResourceId(); + } + + @Override + @ScriptMethod( description = "Returns if the data value set is new ans has not yet been saved on DHIS2." ) + public boolean isNewResource() + { + return dataValueSet.isNewResource(); + } + + @Override + public boolean isLocal() + { + return dataValueSet.isLocal(); + } + + @Override public boolean isDeleted() + { + return false; + } + + @Nullable + @Override + @ScriptMethod( description = "Returns the date and time when the resource has been updated the last time or null if this is a new resource." ) + public ZonedDateTime getLastUpdated() + { + return dataValueSet.getLastUpdated(); + } + + @Nullable + @Override + @ScriptMethod( description = "Returns the ID of the organisation unit on DHIS2 this data value set holds data for." ) + public String getOrganizationUnitId() + { + return dataValueSet.getOrgUnitId(); + } + + @ScriptMethod( description = "Sets the organization unit ID of the organization unit to which this data value set belongs to on DHIS2 (must not be null).", + args = @ScriptMethodArg( value = "orgUnitId", description = "The organization unit ID to which the data value set belongs to" ), + returnDescription = "Returns true each time." ) + public boolean setOrganizationUnitId( @Nullable String orgUnitId ) + { + if ( orgUnitId == null ) + { + throw new TransformerMappingException( "Organization unit ID of data value set must not be null." ); + } + + //I expect that all orgUnits are in place. In the future, if a dynamic OrgUnit resolution feature should be + // in place, then the logic can be changed to use that feature + Reference orgUnitReference = Reference.createIdReference( orgUnitId ); + if ( organizationUnitService.findOneByReference( orgUnitReference ).isPresent() ) + { + if ( !Objects.equals( dataValueSet.getOrgUnitId(), orgUnitId ) ) + { + dataValueSet.setModified( true ); + } + + dataValueSet.setOrgUnitId( orgUnitId ); + } + else + { + throw new TransformerMappingException( "Organization unit with provided Organization unit ID (" + orgUnitId + ") does not exist." ); + } + + return true; + } + + @Nullable + @Override + public ScriptedTrackedEntityInstance getTrackedEntityInstance() + { + return null; + } + + @Nonnull + @Override + @ScriptMethod( description = "Returns the data set ID on DHIS2 this data value set holds data for." ) + public String getDataSetId() + { + return dataValueSet.getDataSetId(); + } + + @ScriptMethod( description = "Sets the data set ID of the data set to which this data value set belongs to on DHIS2 (must not be null).", + args = @ScriptMethodArg( value = "dataSetId", description = "The data set ID to which the data value set belongs to" ), + returnDescription = "Returns true each time." ) + public boolean setDataSetId( @Nullable String dataSetId ) + { + //TODO: Consider fetching all available dataSets from https://play.dhis2.org/dev/api/dataSets and validate + + if ( dataSetId == null ) + { + throw new TransformerMappingException( "Data set ID of data value set must not be null." ); + } + if ( !Objects.equals( dataValueSet.getDataSetId(), dataSetId ) ) + { + dataValueSet.setModified( true ); + } + dataValueSet.setDataSetId( dataSetId ); + + return true; + } + + @Nonnull + @Override + @ScriptMethod( description = "Returns the period on DHIS2 this data value set holds data for." ) + public String getPeriod() + { + return dataValueSet.getPeriod(); + } + + @ScriptMethod( description = "Sets the period to which this data value set belongs to on DHIS2 (must not be null).", + args = @ScriptMethodArg( value = "period", description = "The period to which the data value set belongs to" ), + returnDescription = "Returns true each time." ) + public boolean setPeriod( @Nullable String period ) + { + + //TODO: Consider to create a PeriodUtils class and add some more comprehensive validation of period + if ( period == null ) + { + throw new TransformerMappingException( "Period of data value set must not be null." ); + } + if ( !Objects.equals( dataValueSet.getPeriod(), period ) ) + { + dataValueSet.setModified( true ); + } + dataValueSet.setPeriod( period ); + + return true; + } + + @Nonnull + @Override + public List getDataValues() + { + return dataValueSet.getDataValues(); + } + + @ScriptMethod( description = "Sets the data value of a data value set (must not be null). " + + "This will be skipped when the specified last updated date is before the current last updated data and the user which has last modified the data value set was not the adapter itself.", + returnDescription = "Returns only true if updating the data value has not been skipped since the specified last updated date is before the current last updated date.", + args = { + @ScriptMethodArg( value = "dataElementReference", description = "The reference object to the data element." ), + @ScriptMethodArg( value = "value", description = "The value that should be set for given data element. The value will be converted to the required type automatically (if possible)." ), + @ScriptMethodArg( value = "lastUpdated", description = "The last updated timestamp of the data value that should be assigned to the data value set. This value can be null if check should not be made." ) + } ) + public boolean setDataValue( @Nonnull Reference dataElementReference, @Nullable Object value, + @Nullable Object lastUpdated ) throws TransformerException + { + + final DataElement dataElement = dataElements.getOptional( dataElementReference ).orElseThrow( () -> + new TransformerScriptException( "Data element \"" + dataElementReference + "\" does not exist." ) ); + ZonedDateTime convertedLastUpdated = ScriptedDateTimeUtils.toZonedDateTime( lastUpdated, valueConverter ); + + return setDataValue( dataElement, value, convertedLastUpdated ); + } + + private boolean setDataValue( @Nonnull DataElement dataElement, @Nullable Object value, + @Nullable ZonedDateTime lastUpdated ) throws TransformerException + { + if ( value == null ) + { + throw new TransformerMappingException( "Data value of data value set must not be null." ); + } + + Object convertedValue; + try + { + convertedValue = valueConverter.convert( value, dataElement.getValueType(), String.class ); + } + catch ( ConversionException e ) + { + throw new TransformerMappingException( "Data value of data element \"" + dataElement.getName() + "\" could not be converted: " + e.getMessage(), e ); + } + + final WritableDataValue dataValue = dataValueSet.getDataValue( dataElement.getId() ); + if ( (lastUpdated != null) && (dataValue.getLastUpdated() != null) && dataValue.getLastUpdated().isAfter( lastUpdated ) ) + { + return false; + } + + if ( !Objects.equals( dataValue.getValue(), convertedValue ) ) + { + dataValueSet.setModified( true ); + } + dataValue.setValue( convertedValue ); + + return true; + } + + @Override + @ScriptMethod( description = "Validates the content of the data value set and throws an exception if the content is invalid." ) + public void validate() throws TransformerException + { + if ( dataValueSet.getOrgUnitId() == null ) + { + throw new TransformerMappingException( "Organization unit ID of data value set has not been specified." ); + } + + if ( dataValueSet.getDataSetId() == null ) + { + throw new TransformerMappingException( "Data set ID of data value set has not been specified." ); + } + + if ( dataValueSet.getPeriod() == null ) + { + throw new TransformerMappingException( "Period of data value set has not been specified." ); + } + + if ( dataValueSet.getDataValues() == null || dataValueSet.getDataValues().isEmpty() ) + { + throw new TransformerMappingException( "No data value for data value set has been specified." ); + } + } +} From 38a7c6a96d111de3ebd89ebe7c5b4c4901b5ca19 Mon Sep 17 00:00:00 2001 From: David Katuscak Date: Wed, 24 Jul 2019 15:08:13 +0200 Subject: [PATCH 04/12] WIP implementation of DataValueSetRule and Repository for it --- .../fhir/metadata/model/DataValueSetRule.java | 123 ++++++++++++++++++ .../DataValueSetRuleRepository.java | 103 +++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/DataValueSetRule.java create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/DataValueSetRuleRepository.java diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/DataValueSetRule.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/DataValueSetRule.java new file mode 100644 index 00000000..8289d5a1 --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/DataValueSetRule.java @@ -0,0 +1,123 @@ +package org.dhis2.fhir.adapter.fhir.metadata.model; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import com.fasterxml.jackson.annotation.JsonFilter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; +import org.dhis2.fhir.adapter.jackson.AdapterBeanPropertyFilter; +import org.dhis2.fhir.adapter.jackson.JsonCacheId; + +import javax.annotation.Nonnull; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.Transient; + +/** + * Rule for data value sets. + * + * @author David Katuscak + */ +@Entity +@Table( name = "fhir_data_value_set_rule" ) +@DiscriminatorValue( "DATA_VALUE_SET" ) +@JsonFilter( value = AdapterBeanPropertyFilter.FILTER_NAME ) +public class DataValueSetRule extends AbstractRule +{ + private static final long serialVersionUID = 5463810804987445631L; + + //TODO: Not sure about scripts yet + private ExecutableScript orgUnitLookupScript; + + private ExecutableScript locationLookupScript; + + public DataValueSetRule() + { + super( DhisResourceType.DATA_VALUE_SET ); + } + + //TODO: Not sure about scripts yet - BEGIN + + @JsonCacheId + @ManyToOne + @JoinColumn( name = "org_lookup_script_id" ) + public ExecutableScript getOrgUnitLookupScript() + { + return orgUnitLookupScript; + } + + public void setOrgUnitLookupScript( ExecutableScript orgUnitLookupScript ) + { + this.orgUnitLookupScript = orgUnitLookupScript; + } + + @JsonCacheId + @ManyToOne + @JoinColumn( name = "loc_lookup_script_id" ) + public ExecutableScript getLocationLookupScript() + { + return locationLookupScript; + } + + public void setLocationLookupScript( ExecutableScript locationLookupScript ) + { + this.locationLookupScript = locationLookupScript; + } + + //Not sure about scripts yet - END + + @Override + @Transient + @JsonIgnore + public boolean isEffectiveFhirCreateEnable() { + return isExpEnabled() && isFhirCreateEnabled(); + } + + @Override + @Transient + @JsonIgnore + public boolean isEffectiveFhirUpdateEnable() { + return isExpEnabled() && isFhirUpdateEnabled(); + } + + @Override + @Transient + @JsonIgnore + public boolean isEffectiveFhirDeleteEnable() { + return isExpEnabled() && isFhirDeleteEnabled(); + } + + @Override public boolean coversExecutedRule( @Nonnull AbstractRule executedRule ) + { + return false; + } +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/DataValueSetRuleRepository.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/DataValueSetRuleRepository.java new file mode 100644 index 00000000..ff16350b --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/DataValueSetRuleRepository.java @@ -0,0 +1,103 @@ +package org.dhis2.fhir.adapter.fhir.metadata.repository; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.fhir.metadata.model.DataValueSetRule; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.querydsl.QuerydslPredicateExecutor; +import org.springframework.data.rest.core.annotation.RepositoryRestResource; +import org.springframework.data.rest.core.annotation.RestResource; +import org.springframework.security.access.prepost.PreAuthorize; + +import javax.annotation.Nonnull; +import java.util.List; +import java.util.UUID; + +/** + * @author David Katuscak + */ +@CacheConfig( cacheManager = "metadataCacheManager", cacheNames = "rule" ) +@RepositoryRestResource +@PreAuthorize( "hasRole('DATA_MAPPING')" ) +public interface DataValueSetRuleRepository extends JpaRepository, + QuerydslPredicateExecutor, MetadataRepository +{ + @Nonnull + @Override + @RestResource( exported = false ) + @PreAuthorize( "true" ) + default Class getEntityType() + { + return DataValueSetRule.class; + } + + @Override + @Nonnull + @CacheEvict( allEntries = true ) + List saveAll( @Nonnull Iterable entities ); + + @Override + @Nonnull + @CachePut( key = "#a0.id" ) + @CacheEvict( allEntries = true ) + S saveAndFlush( @Nonnull S entity ); + + @Override + @Nonnull + @CachePut( key = "#a0.id" ) + @CacheEvict( allEntries = true ) + S save( @Nonnull S entity ); + + @Override + @CacheEvict( allEntries = true ) + void deleteInBatch( @Nonnull Iterable entities ); + + @Override + @CacheEvict( allEntries = true ) + void deleteAllInBatch(); + + @Override + @CacheEvict( key = "#a0" ) + void deleteById( @Nonnull UUID id ); + + @Override + @CacheEvict( key = "#a0.id" ) + void delete( @Nonnull DataValueSetRule entity ); + + @Override + @CacheEvict( allEntries = true ) + void deleteAll( @Nonnull Iterable entities ); + + @Override + @CacheEvict( allEntries = true ) + void deleteAll(); +} From 7fdc386208631460e9cd168ec7ba23c431e257d6 Mon Sep 17 00:00:00 2001 From: David Katuscak Date: Wed, 24 Jul 2019 15:08:46 +0200 Subject: [PATCH 05/12] WIP implementation of FhirToDataValueSetTransformer --- .../FhirToDataValueSetTransformer.java | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/aggregate/FhirToDataValueSetTransformer.java diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/aggregate/FhirToDataValueSetTransformer.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/aggregate/FhirToDataValueSetTransformer.java new file mode 100644 index 00000000..bcd76121 --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/aggregate/FhirToDataValueSetTransformer.java @@ -0,0 +1,170 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.aggregate; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.dhis.aggregate.DataValueSet; +import org.dhis2.fhir.adapter.dhis.aggregate.DataValueSetService; +import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; +import org.dhis2.fhir.adapter.dhis.orgunit.OrganizationUnitService; +import org.dhis2.fhir.adapter.fhir.data.repository.FhirDhisAssignmentRepository; +import org.dhis2.fhir.adapter.fhir.metadata.model.DataValueSetRule; +import org.dhis2.fhir.adapter.fhir.metadata.model.FhirClientResource; +import org.dhis2.fhir.adapter.fhir.metadata.model.RuleInfo; +import org.dhis2.fhir.adapter.fhir.repository.DhisFhirResourceId; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutor; +import org.dhis2.fhir.adapter.fhir.transform.TransformerException; +import org.dhis2.fhir.adapter.fhir.transform.fhir.FhirToDhisDeleteTransformOutcome; +import org.dhis2.fhir.adapter.fhir.transform.fhir.FhirToDhisTransformOutcome; +import org.dhis2.fhir.adapter.fhir.transform.fhir.FhirToDhisTransformerContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.AbstractFhirToDhisTransformer; +import org.dhis2.fhir.adapter.spring.StaticObjectProvider; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Map; +import java.util.Optional; + +/** + * @author David Katuscak + */ +@Component +public class FhirToDataValueSetTransformer extends AbstractFhirToDhisTransformer +{ + private final DataValueSetService dataValueSetService; + + public FhirToDataValueSetTransformer( + @Nonnull ScriptExecutor scriptExecutor, + @Nonnull OrganizationUnitService organizationUnitService, + @Nonnull FhirDhisAssignmentRepository fhirDhisAssignmentRepository, + @Nonnull DataValueSetService dataValueSetService ) + { + super( scriptExecutor, organizationUnitService, new StaticObjectProvider<>( dataValueSetService ), fhirDhisAssignmentRepository ); + + this.dataValueSetService = dataValueSetService; + } + + @Nonnull + @Override + public DhisResourceType getDhisResourceType() + { + return DhisResourceType.DATA_VALUE_SET; + } + + @Nonnull + @Override + public Class getDhisResourceClass() + { + return DataValueSet.class; + } + + @Nonnull + @Override + public Class getRuleClass() + { + return DataValueSetRule.class; + } + + @Nonnull + @Override + protected Optional getResourceById( @Nullable final String id ) + throws TransformerException + { + return Optional.empty(); + } + + @Nonnull + @Override + protected Optional getActiveResource( @Nonnull final FhirToDhisTransformerContext context, + @Nonnull final RuleInfo ruleInfo, @Nonnull final Map scriptVariables, + final boolean sync, final boolean refreshed ) throws TransformerException + { + return Optional.empty(); + } + + @Nonnull + @Override + protected Optional findResourceById( @Nonnull final FhirToDhisTransformerContext context, + @Nonnull final RuleInfo ruleInfo, @Nonnull final String id, + @Nonnull final Map scriptVariables ) + { + return Optional.empty(); + } + + @Override + protected boolean isAlwaysActiveResource( @Nonnull final RuleInfo ruleInfo ) + { + return false; + } + + @Nullable + @Override + protected DataValueSet createResource( @Nonnull final FhirToDhisTransformerContext context, + @Nonnull final RuleInfo ruleInfo, @Nullable final String id, + @Nonnull final Map scriptVariables, final boolean sync, final boolean refreshed ) + throws TransformerException + { + if ( context.isCreationDisabled() ) + { + return null; + } + + //TODO: + return null; + } + + @Nullable + @Override + public FhirToDhisTransformOutcome transform( @Nonnull final FhirClientResource fhirClientResource, + @Nonnull final FhirToDhisTransformerContext context, @Nonnull final IBaseResource input, + @Nonnull final RuleInfo ruleInfo, @Nonnull final Map scriptVariables ) + throws TransformerException + { + //TODO: + return null; + } + + @Nullable + @Override + public FhirToDhisDeleteTransformOutcome transformDeletion( + @Nonnull final FhirClientResource fhirClientResource, @Nonnull final RuleInfo ruleInfo, + @Nonnull final DhisFhirResourceId dhisFhirResourceId ) throws TransformerException + { + return null; + } + + @Override + protected boolean isSyncRequired( @Nonnull final FhirToDhisTransformerContext context, + @Nonnull final RuleInfo ruleInfo, @Nonnull final Map scriptVariables ) + throws TransformerException + { + return context.getFhirRequest().isSync(); + } +} From af8424eceb12723233cd391c18c6409040d259fc Mon Sep 17 00:00:00 2001 From: David Katuscak Date: Thu, 25 Jul 2019 11:23:52 +0200 Subject: [PATCH 06/12] Extend ReadWrite instead of ReadOnly class --- .../provider/dstu3/Dstu3MeasureReportResourceProvider.java | 4 ++-- .../server/provider/r4/R4MeasureReportResourceProvider.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java index 6547ae0e..7ee3bc84 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java @@ -40,7 +40,7 @@ import org.dhis2.fhir.adapter.fhir.model.FhirVersion; import org.dhis2.fhir.adapter.fhir.repository.DhisRepository; import org.dhis2.fhir.adapter.fhir.repository.FhirRepository; -import org.dhis2.fhir.adapter.fhir.server.provider.AbstractReadOnlyResourceProvider; +import org.dhis2.fhir.adapter.fhir.server.provider.AbstractReadWriteResourceProvider; import org.hl7.fhir.dstu3.model.MeasureReport; import org.springframework.stereotype.Component; @@ -55,7 +55,7 @@ * @author David Katuscak */ @Component -public class Dstu3MeasureReportResourceProvider extends AbstractReadOnlyResourceProvider +public class Dstu3MeasureReportResourceProvider extends AbstractReadWriteResourceProvider { public Dstu3MeasureReportResourceProvider( @Nonnull FhirClientResourceRepository fhirClientResourceRepository, @Nonnull FhirClientSystemRepository fhirClientSystemRepository, diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java index 95edc6b4..d34c8f0a 100644 --- a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java @@ -40,7 +40,7 @@ import org.dhis2.fhir.adapter.fhir.model.FhirVersion; import org.dhis2.fhir.adapter.fhir.repository.DhisRepository; import org.dhis2.fhir.adapter.fhir.repository.FhirRepository; -import org.dhis2.fhir.adapter.fhir.server.provider.AbstractReadOnlyResourceProvider; +import org.dhis2.fhir.adapter.fhir.server.provider.AbstractReadWriteResourceProvider; import org.hl7.fhir.r4.model.MeasureReport; import org.springframework.stereotype.Component; @@ -55,7 +55,7 @@ * @author David Katuscak */ @Component -public class R4MeasureReportResourceProvider extends AbstractReadOnlyResourceProvider +public class R4MeasureReportResourceProvider extends AbstractReadWriteResourceProvider { public R4MeasureReportResourceProvider( @Nonnull FhirClientResourceRepository fhirClientResourceRepository, @Nonnull FhirClientSystemRepository fhirClientSystemRepository, From 3e968e188ba8cf7f4ef96fedb1bb30a0ce363a70 Mon Sep 17 00:00:00 2001 From: David Katuscak Date: Fri, 12 Jul 2019 09:08:16 +0200 Subject: [PATCH 07/12] Adds DHIS2 DataValueSet resource type --- .../adapter/dhis/aggregate/DataValueSet.java | 232 ++++++++++++++++++ .../dhis/aggregate/DataValueSetService.java | 40 +++ .../impl/DataValueSetServiceImpl.java | 91 +++++++ .../adapter/dhis/model/DhisResourceType.java | 7 +- .../fhir/metadata/model/AbstractRule.java | 3 +- .../metadata/model/TransformDataType.java | 4 +- ...2_0_0__Add_New_Resource_Type_Into_Enum.sql | 30 +++ 7 files changed, 404 insertions(+), 3 deletions(-) create mode 100644 dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java create mode 100644 dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSetService.java create mode 100644 dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/impl/DataValueSetServiceImpl.java create mode 100644 fhir/src/main/resources/db/migration/production/V1.1.0.42_0_0__Add_New_Resource_Type_Into_Enum.sql diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java new file mode 100644 index 00000000..b24e152e --- /dev/null +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java @@ -0,0 +1,232 @@ +package org.dhis2.fhir.adapter.dhis.aggregate; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.dhis2.fhir.adapter.dhis.model.DhisResource; +import org.dhis2.fhir.adapter.dhis.model.DhisResourceId; +import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; +import org.dhis2.fhir.adapter.dhis.model.WritableDataValue; + +import javax.annotation.Nonnull; +import java.io.Serializable; +import java.time.ZonedDateTime; +import java.util.List; + +/** + * @author David Katuscak + */ +public class DataValueSet implements DhisResource, Serializable +{ +// reporter > reference -> Organisation unit +// period > start/end -> Period +// group > code > text -> Data element +// group > measurescore -> Data value +// +// orgUnit +// period +// dataElement +// dataValue + + private static final long serialVersionUID = 6347075531883647618L; + + @JsonProperty( access = JsonProperty.Access.WRITE_ONLY ) + private boolean deleted; + + @JsonIgnore + private boolean modified; + + @JsonIgnore + private boolean newResource; + + @JsonIgnore + private boolean local; + + @JsonProperty + @JsonInclude( JsonInclude.Include.NON_NULL ) + private ZonedDateTime lastUpdated; + + @JsonProperty( "dataValueSet" ) + @JsonInclude( JsonInclude.Include.NON_NULL ) + private String id; + + @JsonProperty( "dataSet" ) + private String dataSetId; + + @JsonProperty( "orgUnit" ) + private String orgUnitId; + + @JsonProperty + private String period; + + private List dataValues; + + public DataValueSet() + { + super(); + } + + public DataValueSet( @Nonnull String id ) + { + this.id = id; + } + + public DataValueSet( boolean newResource ) + { + this.newResource = newResource; + this.modified = newResource; + this.local = newResource; + } + + @Override + @JsonIgnore + public String getId() + { + return id; + } + + @Override + public void setId( String id ) + { + this.id = id; + } + + @Override + public DhisResourceId getResourceId() + { + return (getId() == null) ? null : new DhisResourceId( DhisResourceType.DATA_VALUE_SET, getId() ); + } + + @Override + public String getOrgUnitId() + { + return orgUnitId; + } + + public void setOrgUnitId( String orgUnitId ) + { + this.orgUnitId = orgUnitId; + } + + public String getPeriod() + { + return period; + } + + public void setPeriod( String period ) + { + this.period = period; + } + + public String getDataSetId() + { + return dataSetId; + } + + public void setDataSetId( String dataSetId ) + { + this.dataSetId = dataSetId; + } + + @JsonIgnore + @Nonnull + @Override + public DhisResourceType getResourceType() + { + return DhisResourceType.DATA_VALUE_SET; + } + + public List getDataValues() + { + return dataValues; + } + + public void setDataValues( List dataValues ) + { + this.dataValues = dataValues; + } + + @Override + public boolean isNewResource() + { + return newResource; + } + + @Override + public void resetNewResource() + { + this.newResource = false; + this.modified = false; + + if ( lastUpdated == null ) + { + lastUpdated = ZonedDateTime.now(); + } + } + + @Override + public boolean isLocal() + { + return local; + } + + public void setLocal( boolean local ) + { + this.local = local; + } + + public boolean isModified() + { + return modified; + } + + public void setModified( boolean modified ) + { + this.modified = modified; + } + + @Override + public boolean isDeleted() + { + return deleted; + } + + @Override + public ZonedDateTime getLastUpdated() + { + return lastUpdated; + } + + public void setLastUpdated( ZonedDateTime lastUpdated ) + { + this.lastUpdated = lastUpdated; + } +} diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSetService.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSetService.java new file mode 100644 index 00000000..30c32d3b --- /dev/null +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSetService.java @@ -0,0 +1,40 @@ +package org.dhis2.fhir.adapter.dhis.aggregate; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import javax.annotation.Nonnull; + +/** + * @author David Katuscak + */ +public interface DataValueSetService +{ + @Nonnull + DataValueSet createOrUpdate( @Nonnull DataValueSet enrollment ); +} diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/impl/DataValueSetServiceImpl.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/impl/DataValueSetServiceImpl.java new file mode 100644 index 00000000..f7c3d02b --- /dev/null +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/impl/DataValueSetServiceImpl.java @@ -0,0 +1,91 @@ +package org.dhis2.fhir.adapter.dhis.aggregate.impl; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.dhis.DhisConflictException; +import org.dhis2.fhir.adapter.dhis.DhisImportUnsuccessfulException; +import org.dhis2.fhir.adapter.dhis.aggregate.DataValueSet; +import org.dhis2.fhir.adapter.dhis.aggregate.DataValueSetService; +import org.dhis2.fhir.adapter.dhis.model.ImportSummaryWebMessage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Nonnull; +import java.util.Objects; + +/** + * @author David Katuscak + */ +@Service +public class DataValueSetServiceImpl implements DataValueSetService +{ + private static final String DATA_VALUE_SETS_URI = "/dataValueSets.json"; + + private final RestTemplate restTemplate; + + @Autowired + public DataValueSetServiceImpl( @Nonnull @Qualifier( "userDhis2RestTemplate" ) RestTemplate restTemplate ) + { + this.restTemplate = restTemplate; + } + + @Nonnull + @Override + public DataValueSet createOrUpdate( @Nonnull final DataValueSet dataValueSet ) + { + final ResponseEntity response; + + try + { + response = restTemplate.postForEntity( DATA_VALUE_SETS_URI, dataValueSet, ImportSummaryWebMessage.class ); + } + catch ( HttpClientErrorException e ) + { + if ( HttpStatus.CONFLICT.equals( e.getStatusCode() ) ) + { + throw new DhisConflictException( "DataValueSet could not be created: " + e.getResponseBodyAsString(), e ); + } + throw e; + } + + final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + + if ( result.isNotSuccessful() ) + { + throw new DhisImportUnsuccessfulException( "Response indicates an unsuccessful DataValueSet import." ); + } + + return dataValueSet; + } +} diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DhisResourceType.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DhisResourceType.java index 654008ad..94d96c78 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DhisResourceType.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DhisResourceType.java @@ -74,7 +74,12 @@ public enum DhisResourceType /** * Resource is a organisation unit. */ - ORGANIZATION_UNIT( "organisationUnits", "ou" ); + ORGANIZATION_UNIT( "organisationUnits", "ou" ), + + /** + * Resource is a Data Value Set. + */ + DATA_VALUE_SET( "dataValueSets", "dvs" ); private static final Map byTypeName = Arrays.stream( values() ).collect( Collectors.toMap( DhisResourceType::getTypeName, v -> v ) ); diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/AbstractRule.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/AbstractRule.java index b5bf83f7..25be8065 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/AbstractRule.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/AbstractRule.java @@ -108,7 +108,8 @@ @JsonSubTypes.Type( value = OrganizationUnitRule.class, name = "ORGANIZATION_UNIT" ), @JsonSubTypes.Type( value = EnrollmentRule.class, name = "ENROLLMENT" ), @JsonSubTypes.Type( value = ProgramMetadataRule.class, name = "PROGRAM_METADATA" ), - @JsonSubTypes.Type( value = ProgramStageMetadataRule.class, name = "PROGRAM_STAGE_METADATA" ) + @JsonSubTypes.Type( value = ProgramStageMetadataRule.class, name = "PROGRAM_STAGE_METADATA" ), + @JsonSubTypes.Type( value = DataValueSetRule.class, name = "DATA_VALUE_SET" ) } ) @JsonFilter( value = AdapterBeanPropertyFilter.FILTER_NAME ) public abstract class AbstractRule extends VersionedBaseMetadata implements Serializable, Comparable, NamedMetadata diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/TransformDataType.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/TransformDataType.java index 0ae3ab47..460f6195 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/TransformDataType.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/TransformDataType.java @@ -42,6 +42,7 @@ public enum TransformDataType DHIS_TRACKED_ENTITY_INSTANCE( null ), DHIS_ENROLLMENT( null ), DHIS_EVENT( null ), + DHIS_DATA_VALUE_SET( null ), FHIR_ENCOUNTER( FhirResourceType.ENCOUNTER ), FHIR_LOCATION( FhirResourceType.LOCATION ), FHIR_ORGANIZATION( FhirResourceType.ORGANIZATION ), @@ -56,7 +57,8 @@ public enum TransformDataType FHIR_PLAN_DEFINITION( FhirResourceType.PLAN_DEFINITION ), FHIR_QUESTIONNAIRE( FhirResourceType.QUESTIONNAIRE ), FHIR_CARE_PLAN( FhirResourceType.CARE_PLAN ), - FHIR_QUESTIONNAIRE_RESPONSE( FhirResourceType.QUESTIONNAIRE_RESPONSE ); + FHIR_QUESTIONNAIRE_RESPONSE( FhirResourceType.QUESTIONNAIRE_RESPONSE ), + FHIR_MEASURE_REPORT( FhirResourceType.MEASURE_REPORT ); private final FhirResourceType fhirResourceType; diff --git a/fhir/src/main/resources/db/migration/production/V1.1.0.42_0_0__Add_New_Resource_Type_Into_Enum.sql b/fhir/src/main/resources/db/migration/production/V1.1.0.42_0_0__Add_New_Resource_Type_Into_Enum.sql new file mode 100644 index 00000000..067659e3 --- /dev/null +++ b/fhir/src/main/resources/db/migration/production/V1.1.0.42_0_0__Add_New_Resource_Type_Into_Enum.sql @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO PROGRAM_STAGE_EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +-- @formatter:off +INSERT INTO fhir_resource_type_enum VALUES ('MEASURE_REPORT'); \ No newline at end of file From 32b290e98eebc930029a0a278f401db119c79318 Mon Sep 17 00:00:00 2001 From: David Katuscak Date: Wed, 24 Jul 2019 15:06:19 +0200 Subject: [PATCH 08/12] Add ImportSummariesWebMessage class and adjusts code --- .../dhis/model/ImportSummariesWebMessage.java | 60 +++++++++++++++++++ .../dhis/model/ImportSummaryWebMessage.java | 17 +++--- .../program/impl/EnrollmentServiceImpl.java | 26 ++++---- .../program/impl/EventServiceImpl.java | 32 +++++----- .../impl/TrackedEntityServiceImpl.java | 26 ++++---- 5 files changed, 109 insertions(+), 52 deletions(-) create mode 100644 dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummariesWebMessage.java diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummariesWebMessage.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummariesWebMessage.java new file mode 100644 index 00000000..c678ead1 --- /dev/null +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummariesWebMessage.java @@ -0,0 +1,60 @@ +package org.dhis2.fhir.adapter.dhis.model; + +/* + * Copyright (c) 2004-2018, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * The web message that contains (1 to many) import summaries for creating and updating + * DHIS2 resources. + * + * @author David Katuscak + */ +public class ImportSummariesWebMessage extends WebMessage +{ + private static final long serialVersionUID = -7713823944527785249L; + + private ImportSummaries response; + + public ImportSummaries getResponse() + { + return response; + } + + public void setResponse( ImportSummaries response ) + { + this.response = response; + } + + public boolean isNotSuccessful() + { + return (getStatus() != Status.OK) || + (getResponse().getImportSummaries().size() != 1) || + (getResponse().getImportSummaries().get( 0 ).getStatus() != ImportStatus.SUCCESS) || + (getResponse().getImportSummaries().get( 0 ).getReference() == null); + } +} diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummaryWebMessage.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummaryWebMessage.java index 834e09c0..69d18af9 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummaryWebMessage.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImportSummaryWebMessage.java @@ -1,7 +1,7 @@ package org.dhis2.fhir.adapter.dhis.model; /* - * Copyright (c) 2004-2018, University of Oslo + * Copyright (c) 2004-2019, University of Oslo * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,32 +29,29 @@ */ /** - * The web message that contains import summaries for creating and updating + * The web message that contains (1) import summary for creating and updating * DHIS2 resources. * * @author volsch */ -public class ImportSummaryWebMessage extends WebMessage +public class ImportSummaryWebMessage extends WebMessage { private static final long serialVersionUID = -7713823944527785249L; - private ImportSummaries response; + private ImportSummary response; - public ImportSummaries getResponse() + public ImportSummary getResponse() { return response; } - public void setResponse( ImportSummaries response ) + public void setResponse( ImportSummary response ) { this.response = response; } public boolean isNotSuccessful() { - return (getStatus() != Status.OK) || - (getResponse().getImportSummaries().size() != 1) || - (getResponse().getImportSummaries().get( 0 ).getStatus() != ImportStatus.SUCCESS) || - (getResponse().getImportSummaries().get( 0 ).getReference() == null); + return getStatus() != Status.OK; } } diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EnrollmentServiceImpl.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EnrollmentServiceImpl.java index b7c2977a..43a34c23 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EnrollmentServiceImpl.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EnrollmentServiceImpl.java @@ -41,8 +41,8 @@ import org.dhis2.fhir.adapter.dhis.model.DhisResourceComparator; import org.dhis2.fhir.adapter.dhis.model.ImportStatus; import org.dhis2.fhir.adapter.dhis.model.ImportSummaries; +import org.dhis2.fhir.adapter.dhis.model.ImportSummariesWebMessage; import org.dhis2.fhir.adapter.dhis.model.ImportSummary; -import org.dhis2.fhir.adapter.dhis.model.ImportSummaryWebMessage; import org.dhis2.fhir.adapter.dhis.model.Status; import org.dhis2.fhir.adapter.dhis.tracker.program.Enrollment; import org.dhis2.fhir.adapter.dhis.tracker.program.EnrollmentService; @@ -207,7 +207,7 @@ public Enrollment createOrUpdate( @Nonnull Enrollment enrollment ) @Nonnull protected Enrollment _create( @Nonnull Enrollment enrollment ) { - final ResponseEntity response; + final ResponseEntity response; if ( enrollment.getId() == null ) { @@ -230,7 +230,7 @@ protected Enrollment _create( @Nonnull Enrollment enrollment ) try { response = restTemplate.exchange( ENROLLMENT_CREATE_URI, HttpMethod.PUT, new HttpEntity<>( enrollment ), - ImportSummaryWebMessage.class, enrollment.getId() ); + ImportSummariesWebMessage.class, enrollment.getId() ); } catch ( HttpClientErrorException e ) { @@ -242,7 +242,7 @@ protected Enrollment _create( @Nonnull Enrollment enrollment ) throw e; } - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); if ( result.isNotSuccessful() ) { @@ -283,11 +283,11 @@ protected Enrollment _update( @Nonnull Enrollment enrollment ) // update of included events is not supported enrollment.setEvents( Collections.emptyList() ); - final ResponseEntity response; + final ResponseEntity response; try { response = restTemplate.exchange( ENROLLMENT_UPDATE_URI, HttpMethod.PUT, new HttpEntity<>( enrollment ), - ImportSummaryWebMessage.class, enrollment.getId() ); + ImportSummariesWebMessage.class, enrollment.getId() ); } catch ( HttpClientErrorException e ) { @@ -299,7 +299,7 @@ protected Enrollment _update( @Nonnull Enrollment enrollment ) throw e; } - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); if ( result.getStatus() != Status.OK ) { @@ -327,10 +327,10 @@ public void persistSave( @Nonnull Collection resources, boolean crea final List enrollments = resources.stream().sorted( DhisResourceComparator.INSTANCE ).collect( Collectors.toList() ); enrollments.forEach( e -> e.setEvents( Collections.emptyList() ) ); - final ResponseEntity response = - restTemplate.postForEntity( create ? ENROLLMENT_CREATES_URI : ENROLLMENT_UPDATES_URI, new DhisEnrollments( enrollments ), ImportSummaryWebMessage.class ); + final ResponseEntity response = + restTemplate.postForEntity( create ? ENROLLMENT_CREATES_URI : ENROLLMENT_UPDATES_URI, new DhisEnrollments( enrollments ), ImportSummariesWebMessage.class ); - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); final int size = enrollments.size(); if ( result.getStatus() != Status.OK || result.getResponse() == null || result.getResponse().getImportSummaries().size() != size ) @@ -406,10 +406,10 @@ public void persistDeleteById( @Nonnull Collection ids, @Nullable Consum } final List Enrollments = ids.stream().map( Enrollment::new ).sorted( DhisResourceComparator.INSTANCE ).collect( Collectors.toList() ); - final ResponseEntity response = - restTemplate.postForEntity( ENROLLMENT_DELETES_URI, new DhisEnrollments( Enrollments ), ImportSummaryWebMessage.class ); + final ResponseEntity response = + restTemplate.postForEntity( ENROLLMENT_DELETES_URI, new DhisEnrollments( Enrollments ), ImportSummariesWebMessage.class ); - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); final int size = Enrollments.size(); if ( result.getStatus() != Status.OK || result.getResponse() == null || result.getResponse().getImportSummaries().size() != size ) diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EventServiceImpl.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EventServiceImpl.java index b1f6bea6..6d7e7279 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EventServiceImpl.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/EventServiceImpl.java @@ -46,8 +46,8 @@ import org.dhis2.fhir.adapter.dhis.model.DhisResourceComparator; import org.dhis2.fhir.adapter.dhis.model.DhisResourceResult; import org.dhis2.fhir.adapter.dhis.model.ImportStatus; +import org.dhis2.fhir.adapter.dhis.model.ImportSummariesWebMessage; import org.dhis2.fhir.adapter.dhis.model.ImportSummary; -import org.dhis2.fhir.adapter.dhis.model.ImportSummaryWebMessage; import org.dhis2.fhir.adapter.dhis.model.Status; import org.dhis2.fhir.adapter.dhis.model.UriFilterApplier; import org.dhis2.fhir.adapter.dhis.tracker.program.Event; @@ -173,10 +173,10 @@ public void persistDeleteById( @Nonnull Collection ids, @Nullable Consum } final List Events = ids.stream().map( Event::new ).sorted( DhisResourceComparator.INSTANCE ).collect( Collectors.toList() ); - final ResponseEntity response = - restTemplate.postForEntity( DELETES_URI, new DhisEvents( Events ), ImportSummaryWebMessage.class ); + final ResponseEntity response = + restTemplate.postForEntity( DELETES_URI, new DhisEvents( Events ), ImportSummariesWebMessage.class ); - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); final int size = Events.size(); if ( result.getStatus() != Status.OK || result.getResponse() == null || result.getResponse().getImportSummaries().size() != size ) @@ -241,10 +241,10 @@ public void persistSave( @Nonnull Collection resources, boolean create, @ } final List events = resources.stream().sorted( DhisResourceComparator.INSTANCE ).collect( Collectors.toList() ); - final ResponseEntity response = - restTemplate.postForEntity( create ? CREATES_URI : UPDATES_URI, new DhisEvents( events ), ImportSummaryWebMessage.class ); + final ResponseEntity response = + restTemplate.postForEntity( create ? CREATES_URI : UPDATES_URI, new DhisEvents( events ), ImportSummariesWebMessage.class ); - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); final int size = events.size(); if ( result.getStatus() != Status.OK || result.getResponse() == null || result.getResponse().getImportSummaries().size() != size ) @@ -373,7 +373,7 @@ public Instant poll( @Nonnull DhisSyncGroup group, @Nonnull Instant lastUpdated, @Nonnull protected Event create( @Nonnull Event event ) { - final ResponseEntity response; + final ResponseEntity response; if ( event.getId() == null ) { @@ -383,7 +383,7 @@ protected Event create( @Nonnull Event event ) try { response = restTemplate.exchange( CREATE_URI, HttpMethod.PUT, new HttpEntity<>( event ), - ImportSummaryWebMessage.class, event.getId() ); + ImportSummariesWebMessage.class, event.getId() ); } catch ( HttpClientErrorException e ) { @@ -395,7 +395,7 @@ protected Event create( @Nonnull Event event ) throw e; } - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); if ( result.isNotSuccessful() ) { @@ -412,12 +412,12 @@ protected Event create( @Nonnull Event event ) @Nonnull protected Event update( @Nonnull Event event ) { - final ResponseEntity response; + final ResponseEntity response; try { response = restTemplate.exchange( UPDATE_URI, HttpMethod.PUT, new HttpEntity<>( event ), - ImportSummaryWebMessage.class, event.getId() ); + ImportSummariesWebMessage.class, event.getId() ); } catch ( HttpClientErrorException e ) { @@ -429,7 +429,7 @@ protected Event update( @Nonnull Event event ) throw e; } - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); if ( result.getStatus() != Status.OK ) { @@ -474,11 +474,11 @@ public DhisResourceResult find( @Nonnull String programId, @Nonnull Strin protected void update( @Nonnull MinimalEvent event ) { - final ResponseEntity response; + final ResponseEntity response; try { response = restTemplate.exchange( UPDATE_DATA_VALUE_URI, HttpMethod.PUT, new HttpEntity<>( event ), - ImportSummaryWebMessage.class, event.getId(), event.getDataElementId() ); + ImportSummariesWebMessage.class, event.getId(), event.getDataElementId() ); } catch ( HttpClientErrorException e ) { @@ -488,7 +488,7 @@ protected void update( @Nonnull MinimalEvent event ) } throw e; } - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); if ( result.getStatus() != Status.OK ) { diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/impl/TrackedEntityServiceImpl.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/impl/TrackedEntityServiceImpl.java index 184d2674..badb13c9 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/impl/TrackedEntityServiceImpl.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/impl/TrackedEntityServiceImpl.java @@ -47,8 +47,8 @@ import org.dhis2.fhir.adapter.dhis.model.DhisResourceResult; import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; import org.dhis2.fhir.adapter.dhis.model.ImportStatus; +import org.dhis2.fhir.adapter.dhis.model.ImportSummariesWebMessage; import org.dhis2.fhir.adapter.dhis.model.ImportSummary; -import org.dhis2.fhir.adapter.dhis.model.ImportSummaryWebMessage; import org.dhis2.fhir.adapter.dhis.model.Status; import org.dhis2.fhir.adapter.dhis.model.UriFilterApplier; import org.dhis2.fhir.adapter.dhis.sync.DhisLastUpdated; @@ -293,10 +293,10 @@ public void persistSave( @Nonnull Collection resources, b trackedEntityInstances.forEach( this::clear ); - final ResponseEntity response = - restTemplate.postForEntity( create ? CREATES_URI : UPDATES_URI, new TrackedEntityInstances( trackedEntityInstances ), ImportSummaryWebMessage.class ); + final ResponseEntity response = + restTemplate.postForEntity( create ? CREATES_URI : UPDATES_URI, new TrackedEntityInstances( trackedEntityInstances ), ImportSummariesWebMessage.class ); - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); final int size = trackedEntityInstances.size(); if ( result.getStatus() != Status.OK || result.getResponse() == null || result.getResponse().getImportSummaries().size() != size ) @@ -375,10 +375,10 @@ public void persistDeleteById( @Nonnull Collection ids, @Nullable Consum } final List trackedEntityInstances = ids.stream().map( TrackedEntityInstance::new ).sorted( DhisResourceComparator.INSTANCE ).collect( Collectors.toList() ); - final ResponseEntity response = - restTemplate.postForEntity( DELETES_URI, new TrackedEntityInstances( trackedEntityInstances ), ImportSummaryWebMessage.class ); + final ResponseEntity response = + restTemplate.postForEntity( DELETES_URI, new TrackedEntityInstances( trackedEntityInstances ), ImportSummariesWebMessage.class ); - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); final int size = trackedEntityInstances.size(); if ( result.getStatus() != Status.OK || result.getResponse() == null || result.getResponse().getImportSummaries().size() != size ) @@ -457,7 +457,7 @@ protected TrackedEntityInstance create( @Nonnull TrackedEntityInstance trackedEn { final DhisSyncGroup syncGroup = storedItemService.findSyncGroupById( DhisSyncGroup.DEFAULT_ID ) .orElseThrow( () -> new DhisResourceException( "Could not load default DHIS2 sync group." ) ); - final ResponseEntity response; + final ResponseEntity response; if ( trackedEntityInstance.getId() == null ) { @@ -467,7 +467,7 @@ protected TrackedEntityInstance create( @Nonnull TrackedEntityInstance trackedEn try { clear( trackedEntityInstance ); - response = restTemplate.postForEntity( CREATE_URI, trackedEntityInstance, ImportSummaryWebMessage.class, trackedEntityInstance.getId() ); + response = restTemplate.postForEntity( CREATE_URI, trackedEntityInstance, ImportSummariesWebMessage.class, trackedEntityInstance.getId() ); } catch ( HttpClientErrorException e ) { @@ -479,7 +479,7 @@ protected TrackedEntityInstance create( @Nonnull TrackedEntityInstance trackedEn throw e; } - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); if ( result.isNotSuccessful() ) { @@ -500,12 +500,12 @@ protected TrackedEntityInstance update( @Nonnull TrackedEntityInstance trackedEn final DhisSyncGroup syncGroup = storedItemService.findSyncGroupById( DhisSyncGroup.DEFAULT_ID ) .orElseThrow( () -> new DhisResourceException( "Could not load default DHIS2 sync group." ) ); - final ResponseEntity response; + final ResponseEntity response; try { clear( trackedEntityInstance ); response = restTemplate.exchange( UPDATE_URI, HttpMethod.PUT, new HttpEntity<>( trackedEntityInstance ), - ImportSummaryWebMessage.class, trackedEntityInstance.getId() ); + ImportSummariesWebMessage.class, trackedEntityInstance.getId() ); } catch ( HttpClientErrorException e ) { @@ -515,7 +515,7 @@ protected TrackedEntityInstance update( @Nonnull TrackedEntityInstance trackedEn } throw e; } - final ImportSummaryWebMessage result = Objects.requireNonNull( response.getBody() ); + final ImportSummariesWebMessage result = Objects.requireNonNull( response.getBody() ); if ( result.getStatus() != Status.OK ) { throw new DhisImportUnsuccessfulException( "Response indicates an unsuccessful import of tracked entity instance: " + result.getStatus() ); From 1d8039388e67d1aa9afbb4ec2d974f0760713614 Mon Sep 17 00:00:00 2001 From: David Katuscak Date: Wed, 24 Jul 2019 15:07:23 +0200 Subject: [PATCH 09/12] WIP implementation of MeasureReport -> DataValueSets tranformation --- .../adapter/dhis/aggregate/DataValueSet.java | 71 +++- .../fhir/adapter/dhis/model/DataElements.java | 127 +++++++ .../sync/impl/DhisResourceRepositoryImpl.java | 64 +++- .../Dstu3MeasureReportResourceProvider.java | 80 +++++ .../r4/R4MeasureReportResourceProvider.java | 80 +++++ .../DataValueSetRuleEventListener.java | 42 +++ ...reCreateSaveDataValueSetRuleValidator.java | 61 ++++ .../scripted/ScriptedDataValueSet.java | 53 +++ .../WritableScriptedDataValueSet.java | 319 ++++++++++++++++++ 9 files changed, 881 insertions(+), 16 deletions(-) create mode 100644 dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataElements.java create mode 100644 fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java create mode 100644 fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/listener/DataValueSetRuleEventListener.java create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveDataValueSetRuleValidator.java create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/ScriptedDataValueSet.java create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/WritableScriptedDataValueSet.java diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java index b24e152e..5d22a0e7 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/aggregate/DataValueSet.java @@ -31,6 +31,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import org.dhis2.fhir.adapter.dhis.model.DataValue; import org.dhis2.fhir.adapter.dhis.model.DhisResource; import org.dhis2.fhir.adapter.dhis.model.DhisResourceId; import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; @@ -39,7 +40,9 @@ import javax.annotation.Nonnull; import java.io.Serializable; import java.time.ZonedDateTime; +import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * @author David Katuscak @@ -104,6 +107,7 @@ public DataValueSet( boolean newResource ) this.newResource = newResource; this.modified = newResource; this.local = newResource; + this.dataValues = new ArrayList<>(); } @Override @@ -164,16 +168,6 @@ public DhisResourceType getResourceType() return DhisResourceType.DATA_VALUE_SET; } - public List getDataValues() - { - return dataValues; - } - - public void setDataValues( List dataValues ) - { - this.dataValues = dataValues; - } - @Override public boolean isNewResource() { @@ -229,4 +223,61 @@ public void setLastUpdated( ZonedDateTime lastUpdated ) { this.lastUpdated = lastUpdated; } + + public List getDataValues() + { + return dataValues; + } + + public void setDataValues( List dataValues ) + { + this.dataValues = dataValues; + } + + public boolean containsDataValue( @Nonnull String dataElementId ) + { + return getDataValues().stream().anyMatch( dv -> Objects.equals( dataElementId, dv.getDataElementId() ) ); + } + + public boolean containsDataValue( @Nonnull String dataElementId, @Nonnull String value ) + { + return getDataValues().stream() + .anyMatch( dv -> Objects.equals( dataElementId, dv.getDataElementId() ) + && dv.getValue() != null + && Objects.equals( value, String.valueOf( dv.getValue() ) ) ); + } + + public boolean containsDataValueWithValue( @Nonnull String dataElementId ) + { + return getDataValues().stream() + .filter( dv -> ( dv.getValue() != null ) ) + .anyMatch( dv -> Objects.equals( dataElementId, dv.getDataElementId() ) ); + } + + @Nonnull + public WritableDataValue getDataValue( @Nonnull String dataElementId ) + { + if ( getDataValues() == null ) + { + setDataValues( new ArrayList<>() ); + } + + WritableDataValue dataValue = getDataValues().stream() + .filter( dv -> Objects.equals( dataElementId, dv.getDataElementId() ) ) + .findFirst() + .orElse( null ); + + if ( dataValue == null ) + { + dataValue = new WritableDataValue( dataElementId, true ); + getDataValues().add( dataValue ); + } + return dataValue; + } + + @JsonIgnore + public boolean isAnyDataValueModified() + { + return (getDataValues() != null) && getDataValues().stream().anyMatch( DataValue::isModified ); + } } diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataElements.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataElements.java new file mode 100644 index 00000000..0366f269 --- /dev/null +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataElements.java @@ -0,0 +1,127 @@ +package org.dhis2.fhir.adapter.dhis.model; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.commons.lang3.StringUtils; + +import javax.annotation.Nonnull; +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * @author David Katuscak + */ +public class DataElements implements Serializable +{ + private static final long serialVersionUID = -4563360527610569923L; + + @JsonProperty( "dataElements" ) + private Collection dataElements; + + @JsonIgnore + private transient volatile Map dataElementsById; + + @JsonIgnore + private transient volatile Map dataElementsByName; + + @JsonIgnore + private transient volatile Map dataElementsByCode; + + public DataElements() + { + this.dataElements = Collections.emptyList(); + } + + public DataElements( @Nonnull Collection dataElements ) + { + this.dataElements = dataElements; + } + + @Nonnull + public Optional getOptional( @Nonnull Reference reference ) + { + switch ( reference.getType() ) + { + case CODE: + return getOptionalByCode( reference.getValue() ); + case NAME: + return getOptionalByName( reference.getValue() ); + case ID: + return getOptionalById( reference.getValue() ); + default: + throw new AssertionError( "Unhandled reference type: " + reference.getType() ); + } + } + + @Nonnull + public Optional getOptionalById( @Nonnull String id ) + { + Map tempDataElementsById = dataElementsById; + if ( tempDataElementsById == null ) + { + dataElementsById = tempDataElementsById = dataElements.stream() + .map( ImmutableDataElement::new ) + .collect( Collectors.toMap( DataElement::getId, de -> de ) ); + } + return Optional.ofNullable( tempDataElementsById.get( id ) ); + } + + @Nonnull + public Optional getOptionalByCode( @Nonnull String code ) + { + Map tempDataElementsByCode = dataElementsByCode; + if ( tempDataElementsByCode == null ) + { + dataElementsByCode = tempDataElementsByCode = dataElements.stream() + .filter( de -> StringUtils.isNotBlank( de.getCode() ) ) + .map( ImmutableDataElement::new ) + .collect( Collectors.toMap( DataElement::getCode, de -> de ) ); + } + return Optional.ofNullable( tempDataElementsByCode.get( code ) ); + } + + @Nonnull + public Optional getOptionalByName( @Nonnull String name ) + { + Map tempDataElementsByName = dataElementsByName; + if ( tempDataElementsByName == null ) + { + dataElementsByName = tempDataElementsByName = dataElements.stream() + .map( ImmutableDataElement::new ) + .collect( Collectors.toMap( DataElement::getName, de -> de ) ); + } + return Optional.ofNullable( tempDataElementsByName.get( name ) ); + } +} diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/sync/impl/DhisResourceRepositoryImpl.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/sync/impl/DhisResourceRepositoryImpl.java index fef873ad..ec2fd02d 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/sync/impl/DhisResourceRepositoryImpl.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/sync/impl/DhisResourceRepositoryImpl.java @@ -28,6 +28,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import org.dhis2.fhir.adapter.dhis.aggregate.DataValueSet; +import org.dhis2.fhir.adapter.dhis.aggregate.DataValueSetService; import org.dhis2.fhir.adapter.dhis.model.DhisResource; import org.dhis2.fhir.adapter.dhis.model.DhisResourceId; import org.dhis2.fhir.adapter.dhis.model.Reference; @@ -55,6 +57,7 @@ * * @author volsch * @author Charles Chigoriwa (ITINORDIC) + * @author David Katuscak */ @Component public class DhisResourceRepositoryImpl implements DhisResourceRepository @@ -71,14 +74,17 @@ public class DhisResourceRepositoryImpl implements DhisResourceRepository private final EventService eventService; + private final DataValueSetService dataValueSetService; + public DhisResourceRepositoryImpl( @Nonnull OrganizationUnitService organizationUnitService, ProgramMetadataService programMetadataService, - @Nonnull TrackedEntityService trackedEntityService, @Nonnull EnrollmentService enrollmentService, @Nonnull EventService eventService ) + @Nonnull TrackedEntityService trackedEntityService, @Nonnull EnrollmentService enrollmentService, @Nonnull EventService eventService, @Nonnull DataValueSetService dataValueSetService ) { this.organizationUnitService = organizationUnitService; this.programMetadataService = programMetadataService; this.trackedEntityService = trackedEntityService; this.enrollmentService = enrollmentService; this.eventService = eventService; + this.dataValueSetService = dataValueSetService; } @Nonnull @@ -97,8 +103,10 @@ public Optional findRefreshed( @Nonnull DhisResourceId d return eventService.findOneById( dhisResourceId.getId() ); case ENROLLMENT: return enrollmentService.findOneById( dhisResourceId.getId() ); + case DATA_VALUE_SET: + throw new UnsupportedOperationException( "Finding DHIS2 DataValueSet resources is not supported." ); default: - throw new AssertionError( "Unhandled DHIS resource type: " + dhisResourceId.getType() ); + throw new AssertionError( "Unhandled DHIS2 resource type: " + dhisResourceId.getType() ); } } @@ -114,9 +122,10 @@ public Optional findRefreshedDeleted( @Nonnull DhisResou case PROGRAM_METADATA: case TRACKED_ENTITY: case ENROLLMENT: - throw new UnsupportedOperationException( "Retrieving deleted " + dhisResourceId.getType() + " DHIS resource items is not supported." ); + case DATA_VALUE_SET: + throw new UnsupportedOperationException( "Retrieving deleted " + dhisResourceId.getType() + " DHIS2 resource items is not supported." ); default: - throw new AssertionError( "Unhandled DHIS resource type: " + dhisResourceId.getType() ); + throw new AssertionError( "Unhandled DHIS2 resource type: " + dhisResourceId.getType() ); } } @@ -143,8 +152,11 @@ public DhisResource save( @Nonnull DhisResource resource ) case PROGRAM_STAGE_EVENT: saveEvent( (Event) resource ); break; + case DATA_VALUE_SET: + saveDataValueSet( (DataValueSet) resource ); + break; default: - throw new AssertionError( "Unhandled DHIS resource type: " + resource.getResourceType() ); + throw new AssertionError( "Unhandled DHIS2 resource type: " + resource.getResourceType() ); } return resource; } @@ -160,8 +172,10 @@ public boolean delete( @Nonnull DhisResource resource ) return enrollmentService.delete( resource.getId() ); case PROGRAM_STAGE_EVENT: return eventService.delete( resource.getId() ); + case DATA_VALUE_SET: + throw new UnsupportedOperationException( "Deleting DHIS2 DataValueSet resources is nut supported." ); default: - throw new AssertionError( "Unhandled DHIS resource type: " + resource.getResourceType() ); + throw new AssertionError( "Unhandled DHIS2 resource type: " + resource.getResourceType() ); } } @@ -255,4 +269,42 @@ else if ( enrollment.isModified() ) return updated; } + + private boolean saveDataValueSet( @Nonnull DataValueSet dataValueSet ) + { + if ( validateDataValueSet( dataValueSet ) ) + { + if ( dataValueSet.isNewResource() ) + { + logger.info( "Creating new DataValueSet." ); + dataValueSetService.createOrUpdate( dataValueSet ); + logger.info( "Created new DataValueSet for dataSetId: {}, orgUnit: {}, period: {}.", + dataValueSet.getDataSetId(), dataValueSet.getOrgUnitId(), dataValueSet.getPeriod() ); + return true; + } + else if ( dataValueSet.isModified() ) + { + logger.info( "Updating existing DataValueSet." ); + dataValueSetService.createOrUpdate( dataValueSet ); + logger.info( "Created new DataValueSet for dataSetId: {}, orgUnit: {}, period: {}.", + dataValueSet.getDataSetId(), dataValueSet.getOrgUnitId(), dataValueSet.getPeriod() ); + return true; + } + } + + return false; + } + + private boolean validateDataValueSet( @Nonnull DataValueSet dataValueSet ) + { + if ( dataValueSet.getDataSetId() != null && !dataValueSet.getDataSetId().isEmpty() && + dataValueSet.getOrgUnitId() != null && !dataValueSet.getOrgUnitId().isEmpty() && + dataValueSet.getPeriod() != null && !dataValueSet.getPeriod().isEmpty() && + dataValueSet.getDataValues() != null && !dataValueSet.getDataValues().isEmpty() ) + { + return true; + } + + return false; + } } diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java new file mode 100644 index 00000000..6547ae0e --- /dev/null +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java @@ -0,0 +1,80 @@ +package org.dhis2.fhir.adapter.fhir.server.provider.dstu3; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import ca.uhn.fhir.rest.annotation.Count; +import ca.uhn.fhir.rest.annotation.OptionalParam; +import ca.uhn.fhir.rest.annotation.RawParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.param.DateRangeParam; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirClientResourceRepository; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirClientSystemRepository; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.repository.DhisRepository; +import org.dhis2.fhir.adapter.fhir.repository.FhirRepository; +import org.dhis2.fhir.adapter.fhir.server.provider.AbstractReadOnlyResourceProvider; +import org.hl7.fhir.dstu3.model.MeasureReport; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; + +/** + * DSTU3 resource provider + * + * @author David Katuscak + */ +@Component +public class Dstu3MeasureReportResourceProvider extends AbstractReadOnlyResourceProvider +{ + public Dstu3MeasureReportResourceProvider( @Nonnull FhirClientResourceRepository fhirClientResourceRepository, + @Nonnull FhirClientSystemRepository fhirClientSystemRepository, + @Nonnull FhirRepository fhirRepository, @Nonnull DhisRepository dhisRepository ) + { + super( MeasureReport.class, fhirClientResourceRepository, fhirClientSystemRepository, fhirRepository, dhisRepository ); + } + + @Nonnull + @Override + public FhirVersion getFhirVersion() + { + return FhirVersion.DSTU3; + } + + @Search( allowUnknownParams = true ) + @Nonnull + public IBundleProvider search( @Nonnull RequestDetails requestDetails, @Nullable @Count Integer count, @Nullable @OptionalParam( name = SP_LAST_UPDATED ) DateRangeParam lastUpdatedDateRange, @Nullable @RawParam Map> filter ) + { + return search( requestDetails, count, null, lastUpdatedDateRange, filter ); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java new file mode 100644 index 00000000..95edc6b4 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java @@ -0,0 +1,80 @@ +package org.dhis2.fhir.adapter.fhir.server.provider.r4; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import ca.uhn.fhir.rest.annotation.Count; +import ca.uhn.fhir.rest.annotation.OptionalParam; +import ca.uhn.fhir.rest.annotation.RawParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.param.DateRangeParam; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirClientResourceRepository; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirClientSystemRepository; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.repository.DhisRepository; +import org.dhis2.fhir.adapter.fhir.repository.FhirRepository; +import org.dhis2.fhir.adapter.fhir.server.provider.AbstractReadOnlyResourceProvider; +import org.hl7.fhir.r4.model.MeasureReport; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; + +/** + * r4 resource provider + * + * @author David Katuscak + */ +@Component +public class R4MeasureReportResourceProvider extends AbstractReadOnlyResourceProvider +{ + public R4MeasureReportResourceProvider( @Nonnull FhirClientResourceRepository fhirClientResourceRepository, + @Nonnull FhirClientSystemRepository fhirClientSystemRepository, + @Nonnull FhirRepository fhirRepository, @Nonnull DhisRepository dhisRepository ) + { + super( MeasureReport.class, fhirClientResourceRepository, fhirClientSystemRepository, fhirRepository, dhisRepository ); + } + + @Nonnull + @Override + public FhirVersion getFhirVersion() + { + return FhirVersion.R4; + } + + @Search( allowUnknownParams = true ) + @Nonnull + public IBundleProvider search( @Nonnull RequestDetails requestDetails, @Nullable @Count Integer count, @Nullable @OptionalParam( name = SP_LAST_UPDATED ) DateRangeParam lastUpdatedDateRange, @Nullable @RawParam Map> filter ) + { + return search( requestDetails, count, null, lastUpdatedDateRange, filter ); + } +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/listener/DataValueSetRuleEventListener.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/listener/DataValueSetRuleEventListener.java new file mode 100644 index 00000000..3e7e600d --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/listener/DataValueSetRuleEventListener.java @@ -0,0 +1,42 @@ +package org.dhis2.fhir.adapter.fhir.metadata.repository.listener; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.fhir.metadata.model.DataValueSetRule; +import org.springframework.stereotype.Component; + +/** + * Event listener that prepares {@link DataValueSetRule} class before saving. + * + * @author David Katuscak + */ +@Component +public class DataValueSetRuleEventListener extends AbstractRuleEventListener +{ +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveDataValueSetRuleValidator.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveDataValueSetRuleValidator.java new file mode 100644 index 00000000..4b9c5dc5 --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveDataValueSetRuleValidator.java @@ -0,0 +1,61 @@ +package org.dhis2.fhir.adapter.fhir.metadata.repository.validator; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.fhir.metadata.model.DataValueSetRule; +import org.dhis2.fhir.adapter.fhir.metadata.model.TransformDataType; +import org.springframework.stereotype.Component; +import org.springframework.validation.Errors; + +import javax.annotation.Nonnull; +import javax.persistence.EntityManager; + +/** + * Spring Data REST validator for {@link DataValueSetRule}. + * + * @author David Katuscak + */ +@Component +public class BeforeCreateSaveDataValueSetRuleValidator extends AbstractBeforeCreateSaveRuleValidator + implements MetadataValidator +{ + public BeforeCreateSaveDataValueSetRuleValidator( @Nonnull EntityManager entityManager ) + { + super( DataValueSetRule.class, entityManager ); + } + + @Override protected void doValidate( @Nonnull DataValueSetRule rule, @Nonnull Errors errors ) + { + validate( rule, TransformDataType.DHIS_DATA_VALUE_SET, errors ); + + //TODO: Do I need to validate some script? E.g. as in Enrollment validator? + BeforeCreateSaveFhirResourceMappingValidator.checkValidOrgLookupScript( errors, "DataValueSetRule.", "orgUnitLookupScript", rule.getFhirResourceType(), rule.getOrgUnitLookupScript() ); + BeforeCreateSaveFhirResourceMappingValidator.checkValidLocationLookupScript( errors, "DataValueSetRule.", "locationLookupScript", rule.getFhirResourceType(), rule.getLocationLookupScript() ); + } +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/ScriptedDataValueSet.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/ScriptedDataValueSet.java new file mode 100644 index 00000000..799cb863 --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/ScriptedDataValueSet.java @@ -0,0 +1,53 @@ +package org.dhis2.fhir.adapter.fhir.transform.scripted; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.dhis.model.WritableDataValue; +import org.dhis2.fhir.adapter.scriptable.Scriptable; + +import javax.annotation.Nonnull; +import java.util.List; + +/** + * Mutable or immutable data value set resource that can be used by scripts safely. + * + * @author David Katuscak + */ +@Scriptable +public interface ScriptedDataValueSet extends ScriptedDhisResource +{ + @Nonnull + String getDataSetId(); + + @Nonnull + String getPeriod(); + + @Nonnull + List getDataValues(); +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/WritableScriptedDataValueSet.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/WritableScriptedDataValueSet.java new file mode 100644 index 00000000..42ed9346 --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/scripted/WritableScriptedDataValueSet.java @@ -0,0 +1,319 @@ +package org.dhis2.fhir.adapter.fhir.transform.scripted; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.converter.ConversionException; +import org.dhis2.fhir.adapter.dhis.aggregate.DataValueSet; +import org.dhis2.fhir.adapter.dhis.converter.ValueConverter; +import org.dhis2.fhir.adapter.dhis.model.DataElement; +import org.dhis2.fhir.adapter.dhis.model.DataElements; +import org.dhis2.fhir.adapter.dhis.model.DataValue; +import org.dhis2.fhir.adapter.dhis.model.DhisResourceId; +import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; +import org.dhis2.fhir.adapter.dhis.model.Reference; +import org.dhis2.fhir.adapter.dhis.model.WritableDataValue; +import org.dhis2.fhir.adapter.dhis.orgunit.OrganizationUnitService; +import org.dhis2.fhir.adapter.dhis.tracker.trackedentity.TrackedEntityAttribute; +import org.dhis2.fhir.adapter.dhis.tracker.trackedentity.TrackedEntityAttributeValue; +import org.dhis2.fhir.adapter.fhir.transform.TransformerException; +import org.dhis2.fhir.adapter.fhir.transform.TransformerMappingException; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.ScriptedDateTimeUtils; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.Serializable; +import java.time.ZonedDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +/** + * Mutable data value set resource that can be used by scripts safely. + * + * @author David Katuscak + */ +@Scriptable +@ScriptType( value = "DataValueSet", var = "dataValueSet", transformDataType = "DHIS_DATA_VALUE_SET", + description = "Data Value Set. If Data Value Set is not new and will be modified, it will be persisted." ) +public class WritableScriptedDataValueSet implements ScriptedDataValueSet, Serializable +{ + private final DataElements dataElements; + + private final DataValueSet dataValueSet; + + private final OrganizationUnitService organizationUnitService; + + private final ValueConverter valueConverter; + + public WritableScriptedDataValueSet ( @Nonnull DataElements dataElements, @Nonnull DataValueSet dataValueSet, + @Nonnull OrganizationUnitService organizationUnitService, @Nonnull ValueConverter valueConverter ) + { + this.dataElements = dataElements; + this.dataValueSet = dataValueSet; + this.organizationUnitService = organizationUnitService; + this.valueConverter = valueConverter; + } + + @Nullable + @Override + @ScriptMethod( description = "Returns the ID of the DataValueSet on DHIS2. Return null if the instance is new." ) + public String getId() + { + return dataValueSet.getId(); + } + + @Nonnull + @Override + public DhisResourceType getResourceType() + { + return dataValueSet.getResourceType(); + } + + @Nullable + @Override + public DhisResourceId getResourceId() + { + return dataValueSet.getResourceId(); + } + + @Override + @ScriptMethod( description = "Returns if the data value set is new ans has not yet been saved on DHIS2." ) + public boolean isNewResource() + { + return dataValueSet.isNewResource(); + } + + @Override + public boolean isLocal() + { + return dataValueSet.isLocal(); + } + + @Override public boolean isDeleted() + { + return false; + } + + @Nullable + @Override + @ScriptMethod( description = "Returns the date and time when the resource has been updated the last time or null if this is a new resource." ) + public ZonedDateTime getLastUpdated() + { + return dataValueSet.getLastUpdated(); + } + + @Nullable + @Override + @ScriptMethod( description = "Returns the ID of the organisation unit on DHIS2 this data value set holds data for." ) + public String getOrganizationUnitId() + { + return dataValueSet.getOrgUnitId(); + } + + @ScriptMethod( description = "Sets the organization unit ID of the organization unit to which this data value set belongs to on DHIS2 (must not be null).", + args = @ScriptMethodArg( value = "orgUnitId", description = "The organization unit ID to which the data value set belongs to" ), + returnDescription = "Returns true each time." ) + public boolean setOrganizationUnitId( @Nullable String orgUnitId ) + { + if ( orgUnitId == null ) + { + throw new TransformerMappingException( "Organization unit ID of data value set must not be null." ); + } + + //I expect that all orgUnits are in place. In the future, if a dynamic OrgUnit resolution feature should be + // in place, then the logic can be changed to use that feature + Reference orgUnitReference = Reference.createIdReference( orgUnitId ); + if ( organizationUnitService.findOneByReference( orgUnitReference ).isPresent() ) + { + if ( !Objects.equals( dataValueSet.getOrgUnitId(), orgUnitId ) ) + { + dataValueSet.setModified( true ); + } + + dataValueSet.setOrgUnitId( orgUnitId ); + } + else + { + throw new TransformerMappingException( "Organization unit with provided Organization unit ID (" + orgUnitId + ") does not exist." ); + } + + return true; + } + + @Nullable + @Override + public ScriptedTrackedEntityInstance getTrackedEntityInstance() + { + return null; + } + + @Nonnull + @Override + @ScriptMethod( description = "Returns the data set ID on DHIS2 this data value set holds data for." ) + public String getDataSetId() + { + return dataValueSet.getDataSetId(); + } + + @ScriptMethod( description = "Sets the data set ID of the data set to which this data value set belongs to on DHIS2 (must not be null).", + args = @ScriptMethodArg( value = "dataSetId", description = "The data set ID to which the data value set belongs to" ), + returnDescription = "Returns true each time." ) + public boolean setDataSetId( @Nullable String dataSetId ) + { + //TODO: Consider fetching all available dataSets from https://play.dhis2.org/dev/api/dataSets and validate + + if ( dataSetId == null ) + { + throw new TransformerMappingException( "Data set ID of data value set must not be null." ); + } + if ( !Objects.equals( dataValueSet.getDataSetId(), dataSetId ) ) + { + dataValueSet.setModified( true ); + } + dataValueSet.setDataSetId( dataSetId ); + + return true; + } + + @Nonnull + @Override + @ScriptMethod( description = "Returns the period on DHIS2 this data value set holds data for." ) + public String getPeriod() + { + return dataValueSet.getPeriod(); + } + + @ScriptMethod( description = "Sets the period to which this data value set belongs to on DHIS2 (must not be null).", + args = @ScriptMethodArg( value = "period", description = "The period to which the data value set belongs to" ), + returnDescription = "Returns true each time." ) + public boolean setPeriod( @Nullable String period ) + { + + //TODO: Consider to create a PeriodUtils class and add some more comprehensive validation of period + if ( period == null ) + { + throw new TransformerMappingException( "Period of data value set must not be null." ); + } + if ( !Objects.equals( dataValueSet.getPeriod(), period ) ) + { + dataValueSet.setModified( true ); + } + dataValueSet.setPeriod( period ); + + return true; + } + + @Nonnull + @Override + public List getDataValues() + { + return dataValueSet.getDataValues(); + } + + @ScriptMethod( description = "Sets the data value of a data value set (must not be null). " + + "This will be skipped when the specified last updated date is before the current last updated data and the user which has last modified the data value set was not the adapter itself.", + returnDescription = "Returns only true if updating the data value has not been skipped since the specified last updated date is before the current last updated date.", + args = { + @ScriptMethodArg( value = "dataElementReference", description = "The reference object to the data element." ), + @ScriptMethodArg( value = "value", description = "The value that should be set for given data element. The value will be converted to the required type automatically (if possible)." ), + @ScriptMethodArg( value = "lastUpdated", description = "The last updated timestamp of the data value that should be assigned to the data value set. This value can be null if check should not be made." ) + } ) + public boolean setDataValue( @Nonnull Reference dataElementReference, @Nullable Object value, + @Nullable Object lastUpdated ) throws TransformerException + { + + final DataElement dataElement = dataElements.getOptional( dataElementReference ).orElseThrow( () -> + new TransformerScriptException( "Data element \"" + dataElementReference + "\" does not exist." ) ); + ZonedDateTime convertedLastUpdated = ScriptedDateTimeUtils.toZonedDateTime( lastUpdated, valueConverter ); + + return setDataValue( dataElement, value, convertedLastUpdated ); + } + + private boolean setDataValue( @Nonnull DataElement dataElement, @Nullable Object value, + @Nullable ZonedDateTime lastUpdated ) throws TransformerException + { + if ( value == null ) + { + throw new TransformerMappingException( "Data value of data value set must not be null." ); + } + + Object convertedValue; + try + { + convertedValue = valueConverter.convert( value, dataElement.getValueType(), String.class ); + } + catch ( ConversionException e ) + { + throw new TransformerMappingException( "Data value of data element \"" + dataElement.getName() + "\" could not be converted: " + e.getMessage(), e ); + } + + final WritableDataValue dataValue = dataValueSet.getDataValue( dataElement.getId() ); + if ( (lastUpdated != null) && (dataValue.getLastUpdated() != null) && dataValue.getLastUpdated().isAfter( lastUpdated ) ) + { + return false; + } + + if ( !Objects.equals( dataValue.getValue(), convertedValue ) ) + { + dataValueSet.setModified( true ); + } + dataValue.setValue( convertedValue ); + + return true; + } + + @Override + @ScriptMethod( description = "Validates the content of the data value set and throws an exception if the content is invalid." ) + public void validate() throws TransformerException + { + if ( dataValueSet.getOrgUnitId() == null ) + { + throw new TransformerMappingException( "Organization unit ID of data value set has not been specified." ); + } + + if ( dataValueSet.getDataSetId() == null ) + { + throw new TransformerMappingException( "Data set ID of data value set has not been specified." ); + } + + if ( dataValueSet.getPeriod() == null ) + { + throw new TransformerMappingException( "Period of data value set has not been specified." ); + } + + if ( dataValueSet.getDataValues() == null || dataValueSet.getDataValues().isEmpty() ) + { + throw new TransformerMappingException( "No data value for data value set has been specified." ); + } + } +} From 3ef93fbf955a02073bd4dbc1ea648461caf30b09 Mon Sep 17 00:00:00 2001 From: David Katuscak Date: Wed, 24 Jul 2019 15:08:13 +0200 Subject: [PATCH 10/12] WIP implementation of DataValueSetRule and Repository for it --- .../fhir/metadata/model/DataValueSetRule.java | 123 ++++++++++++++++++ .../DataValueSetRuleRepository.java | 103 +++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/DataValueSetRule.java create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/DataValueSetRuleRepository.java diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/DataValueSetRule.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/DataValueSetRule.java new file mode 100644 index 00000000..8289d5a1 --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/DataValueSetRule.java @@ -0,0 +1,123 @@ +package org.dhis2.fhir.adapter.fhir.metadata.model; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import com.fasterxml.jackson.annotation.JsonFilter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; +import org.dhis2.fhir.adapter.jackson.AdapterBeanPropertyFilter; +import org.dhis2.fhir.adapter.jackson.JsonCacheId; + +import javax.annotation.Nonnull; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.Transient; + +/** + * Rule for data value sets. + * + * @author David Katuscak + */ +@Entity +@Table( name = "fhir_data_value_set_rule" ) +@DiscriminatorValue( "DATA_VALUE_SET" ) +@JsonFilter( value = AdapterBeanPropertyFilter.FILTER_NAME ) +public class DataValueSetRule extends AbstractRule +{ + private static final long serialVersionUID = 5463810804987445631L; + + //TODO: Not sure about scripts yet + private ExecutableScript orgUnitLookupScript; + + private ExecutableScript locationLookupScript; + + public DataValueSetRule() + { + super( DhisResourceType.DATA_VALUE_SET ); + } + + //TODO: Not sure about scripts yet - BEGIN + + @JsonCacheId + @ManyToOne + @JoinColumn( name = "org_lookup_script_id" ) + public ExecutableScript getOrgUnitLookupScript() + { + return orgUnitLookupScript; + } + + public void setOrgUnitLookupScript( ExecutableScript orgUnitLookupScript ) + { + this.orgUnitLookupScript = orgUnitLookupScript; + } + + @JsonCacheId + @ManyToOne + @JoinColumn( name = "loc_lookup_script_id" ) + public ExecutableScript getLocationLookupScript() + { + return locationLookupScript; + } + + public void setLocationLookupScript( ExecutableScript locationLookupScript ) + { + this.locationLookupScript = locationLookupScript; + } + + //Not sure about scripts yet - END + + @Override + @Transient + @JsonIgnore + public boolean isEffectiveFhirCreateEnable() { + return isExpEnabled() && isFhirCreateEnabled(); + } + + @Override + @Transient + @JsonIgnore + public boolean isEffectiveFhirUpdateEnable() { + return isExpEnabled() && isFhirUpdateEnabled(); + } + + @Override + @Transient + @JsonIgnore + public boolean isEffectiveFhirDeleteEnable() { + return isExpEnabled() && isFhirDeleteEnabled(); + } + + @Override public boolean coversExecutedRule( @Nonnull AbstractRule executedRule ) + { + return false; + } +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/DataValueSetRuleRepository.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/DataValueSetRuleRepository.java new file mode 100644 index 00000000..ff16350b --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/DataValueSetRuleRepository.java @@ -0,0 +1,103 @@ +package org.dhis2.fhir.adapter.fhir.metadata.repository; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.fhir.metadata.model.DataValueSetRule; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.querydsl.QuerydslPredicateExecutor; +import org.springframework.data.rest.core.annotation.RepositoryRestResource; +import org.springframework.data.rest.core.annotation.RestResource; +import org.springframework.security.access.prepost.PreAuthorize; + +import javax.annotation.Nonnull; +import java.util.List; +import java.util.UUID; + +/** + * @author David Katuscak + */ +@CacheConfig( cacheManager = "metadataCacheManager", cacheNames = "rule" ) +@RepositoryRestResource +@PreAuthorize( "hasRole('DATA_MAPPING')" ) +public interface DataValueSetRuleRepository extends JpaRepository, + QuerydslPredicateExecutor, MetadataRepository +{ + @Nonnull + @Override + @RestResource( exported = false ) + @PreAuthorize( "true" ) + default Class getEntityType() + { + return DataValueSetRule.class; + } + + @Override + @Nonnull + @CacheEvict( allEntries = true ) + List saveAll( @Nonnull Iterable entities ); + + @Override + @Nonnull + @CachePut( key = "#a0.id" ) + @CacheEvict( allEntries = true ) + S saveAndFlush( @Nonnull S entity ); + + @Override + @Nonnull + @CachePut( key = "#a0.id" ) + @CacheEvict( allEntries = true ) + S save( @Nonnull S entity ); + + @Override + @CacheEvict( allEntries = true ) + void deleteInBatch( @Nonnull Iterable entities ); + + @Override + @CacheEvict( allEntries = true ) + void deleteAllInBatch(); + + @Override + @CacheEvict( key = "#a0" ) + void deleteById( @Nonnull UUID id ); + + @Override + @CacheEvict( key = "#a0.id" ) + void delete( @Nonnull DataValueSetRule entity ); + + @Override + @CacheEvict( allEntries = true ) + void deleteAll( @Nonnull Iterable entities ); + + @Override + @CacheEvict( allEntries = true ) + void deleteAll(); +} From 0795f21b93761dd4ca5478d031dc35a4cbc9bdbc Mon Sep 17 00:00:00 2001 From: David Katuscak Date: Wed, 24 Jul 2019 15:08:46 +0200 Subject: [PATCH 11/12] WIP implementation of FhirToDataValueSetTransformer --- .../FhirToDataValueSetTransformer.java | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/aggregate/FhirToDataValueSetTransformer.java diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/aggregate/FhirToDataValueSetTransformer.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/aggregate/FhirToDataValueSetTransformer.java new file mode 100644 index 00000000..bcd76121 --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/aggregate/FhirToDataValueSetTransformer.java @@ -0,0 +1,170 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.aggregate; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.dhis.aggregate.DataValueSet; +import org.dhis2.fhir.adapter.dhis.aggregate.DataValueSetService; +import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; +import org.dhis2.fhir.adapter.dhis.orgunit.OrganizationUnitService; +import org.dhis2.fhir.adapter.fhir.data.repository.FhirDhisAssignmentRepository; +import org.dhis2.fhir.adapter.fhir.metadata.model.DataValueSetRule; +import org.dhis2.fhir.adapter.fhir.metadata.model.FhirClientResource; +import org.dhis2.fhir.adapter.fhir.metadata.model.RuleInfo; +import org.dhis2.fhir.adapter.fhir.repository.DhisFhirResourceId; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutor; +import org.dhis2.fhir.adapter.fhir.transform.TransformerException; +import org.dhis2.fhir.adapter.fhir.transform.fhir.FhirToDhisDeleteTransformOutcome; +import org.dhis2.fhir.adapter.fhir.transform.fhir.FhirToDhisTransformOutcome; +import org.dhis2.fhir.adapter.fhir.transform.fhir.FhirToDhisTransformerContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.AbstractFhirToDhisTransformer; +import org.dhis2.fhir.adapter.spring.StaticObjectProvider; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Map; +import java.util.Optional; + +/** + * @author David Katuscak + */ +@Component +public class FhirToDataValueSetTransformer extends AbstractFhirToDhisTransformer +{ + private final DataValueSetService dataValueSetService; + + public FhirToDataValueSetTransformer( + @Nonnull ScriptExecutor scriptExecutor, + @Nonnull OrganizationUnitService organizationUnitService, + @Nonnull FhirDhisAssignmentRepository fhirDhisAssignmentRepository, + @Nonnull DataValueSetService dataValueSetService ) + { + super( scriptExecutor, organizationUnitService, new StaticObjectProvider<>( dataValueSetService ), fhirDhisAssignmentRepository ); + + this.dataValueSetService = dataValueSetService; + } + + @Nonnull + @Override + public DhisResourceType getDhisResourceType() + { + return DhisResourceType.DATA_VALUE_SET; + } + + @Nonnull + @Override + public Class getDhisResourceClass() + { + return DataValueSet.class; + } + + @Nonnull + @Override + public Class getRuleClass() + { + return DataValueSetRule.class; + } + + @Nonnull + @Override + protected Optional getResourceById( @Nullable final String id ) + throws TransformerException + { + return Optional.empty(); + } + + @Nonnull + @Override + protected Optional getActiveResource( @Nonnull final FhirToDhisTransformerContext context, + @Nonnull final RuleInfo ruleInfo, @Nonnull final Map scriptVariables, + final boolean sync, final boolean refreshed ) throws TransformerException + { + return Optional.empty(); + } + + @Nonnull + @Override + protected Optional findResourceById( @Nonnull final FhirToDhisTransformerContext context, + @Nonnull final RuleInfo ruleInfo, @Nonnull final String id, + @Nonnull final Map scriptVariables ) + { + return Optional.empty(); + } + + @Override + protected boolean isAlwaysActiveResource( @Nonnull final RuleInfo ruleInfo ) + { + return false; + } + + @Nullable + @Override + protected DataValueSet createResource( @Nonnull final FhirToDhisTransformerContext context, + @Nonnull final RuleInfo ruleInfo, @Nullable final String id, + @Nonnull final Map scriptVariables, final boolean sync, final boolean refreshed ) + throws TransformerException + { + if ( context.isCreationDisabled() ) + { + return null; + } + + //TODO: + return null; + } + + @Nullable + @Override + public FhirToDhisTransformOutcome transform( @Nonnull final FhirClientResource fhirClientResource, + @Nonnull final FhirToDhisTransformerContext context, @Nonnull final IBaseResource input, + @Nonnull final RuleInfo ruleInfo, @Nonnull final Map scriptVariables ) + throws TransformerException + { + //TODO: + return null; + } + + @Nullable + @Override + public FhirToDhisDeleteTransformOutcome transformDeletion( + @Nonnull final FhirClientResource fhirClientResource, @Nonnull final RuleInfo ruleInfo, + @Nonnull final DhisFhirResourceId dhisFhirResourceId ) throws TransformerException + { + return null; + } + + @Override + protected boolean isSyncRequired( @Nonnull final FhirToDhisTransformerContext context, + @Nonnull final RuleInfo ruleInfo, @Nonnull final Map scriptVariables ) + throws TransformerException + { + return context.getFhirRequest().isSync(); + } +} From c6f40e2f943df723edc8d2f1680938b26bea7bba Mon Sep 17 00:00:00 2001 From: David Katuscak Date: Thu, 25 Jul 2019 11:23:52 +0200 Subject: [PATCH 12/12] Extend ReadWrite instead of ReadOnly class --- .../provider/dstu3/Dstu3MeasureReportResourceProvider.java | 4 ++-- .../server/provider/r4/R4MeasureReportResourceProvider.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java index 6547ae0e..7ee3bc84 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/dstu3/Dstu3MeasureReportResourceProvider.java @@ -40,7 +40,7 @@ import org.dhis2.fhir.adapter.fhir.model.FhirVersion; import org.dhis2.fhir.adapter.fhir.repository.DhisRepository; import org.dhis2.fhir.adapter.fhir.repository.FhirRepository; -import org.dhis2.fhir.adapter.fhir.server.provider.AbstractReadOnlyResourceProvider; +import org.dhis2.fhir.adapter.fhir.server.provider.AbstractReadWriteResourceProvider; import org.hl7.fhir.dstu3.model.MeasureReport; import org.springframework.stereotype.Component; @@ -55,7 +55,7 @@ * @author David Katuscak */ @Component -public class Dstu3MeasureReportResourceProvider extends AbstractReadOnlyResourceProvider +public class Dstu3MeasureReportResourceProvider extends AbstractReadWriteResourceProvider { public Dstu3MeasureReportResourceProvider( @Nonnull FhirClientResourceRepository fhirClientResourceRepository, @Nonnull FhirClientSystemRepository fhirClientSystemRepository, diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java index 95edc6b4..d34c8f0a 100644 --- a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/provider/r4/R4MeasureReportResourceProvider.java @@ -40,7 +40,7 @@ import org.dhis2.fhir.adapter.fhir.model.FhirVersion; import org.dhis2.fhir.adapter.fhir.repository.DhisRepository; import org.dhis2.fhir.adapter.fhir.repository.FhirRepository; -import org.dhis2.fhir.adapter.fhir.server.provider.AbstractReadOnlyResourceProvider; +import org.dhis2.fhir.adapter.fhir.server.provider.AbstractReadWriteResourceProvider; import org.hl7.fhir.r4.model.MeasureReport; import org.springframework.stereotype.Component; @@ -55,7 +55,7 @@ * @author David Katuscak */ @Component -public class R4MeasureReportResourceProvider extends AbstractReadOnlyResourceProvider +public class R4MeasureReportResourceProvider extends AbstractReadWriteResourceProvider { public R4MeasureReportResourceProvider( @Nonnull FhirClientResourceRepository fhirClientResourceRepository, @Nonnull FhirClientSystemRepository fhirClientSystemRepository,