diff --git a/app/pom.xml b/app/pom.xml index 1d220104..686c577e 100644 --- a/app/pom.xml +++ b/app/pom.xml @@ -1,6 +1,6 @@ + + + 4.0.0 + + dhis2-fhir-adapter-fhir-r4 + jar + + + org.dhis2.fhir.adapter + dhis2-fhir-adapter + 1.1.0-SNAPSHOT + .. + + + dhis2-fhir-adapter-fhir-r4 + + The FHIR version R4 specific implementation of classes. This module has + (unlike other modules) access to R4 dependencies of HAPI FHIR. Classes + of this module may be duplicated (with FHIR version specific code changes) + for other FHIR versions in other modules + + + + + org.dhis2.fhir.adapter + dhis2-fhir-adapter-fhir + ${project.version} + + + + ca.uhn.hapi.fhir + hapi-fhir-structures-r4 + + + ca.uhn.hapi.fhir + hapi-fhir-validation-resources-r4 + + + + org.mockito + mockito-core + test + + + diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/config/r4/R4FhirConfig.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/config/r4/R4FhirConfig.java new file mode 100644 index 00000000..b5b350ab --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/config/r4/R4FhirConfig.java @@ -0,0 +1,43 @@ +package org.dhis2.fhir.adapter.fhir.config.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.context.FhirContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class R4FhirConfig +{ + @Bean + protected FhirContext fhirContextR4() + { + return FhirContext.forR4(); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4AdministrativeGenderToStringConverter.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4AdministrativeGenderToStringConverter.java new file mode 100644 index 00000000..f4d7d4df --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4AdministrativeGenderToStringConverter.java @@ -0,0 +1,53 @@ +package org.dhis2.fhir.adapter.fhir.converter.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 org.dhis2.fhir.adapter.converter.ConvertedValueTypes; +import org.dhis2.fhir.adapter.fhir.converter.AbstractAdministrativeGenderToStringConverter; +import org.dhis2.fhir.adapter.fhir.metadata.model.ConstantResolver; +import org.dhis2.fhir.adapter.model.ValueType; +import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; + +/** + * FHIR version R4 implementation of {@link AbstractAdministrativeGenderToStringConverter}. + * + * @author volsch + */ +@Component +@ConvertedValueTypes( types = ValueType.TEXT ) +public class R4AdministrativeGenderToStringConverter extends AbstractAdministrativeGenderToStringConverter +{ + public R4AdministrativeGenderToStringConverter( @Nonnull ConstantResolver constantResolver ) + { + super( AdministrativeGender.class, constantResolver ); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4BaseDateTimeTypeToDateStringConverter.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4BaseDateTimeTypeToDateStringConverter.java new file mode 100644 index 00000000..17c3097c --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4BaseDateTimeTypeToDateStringConverter.java @@ -0,0 +1,50 @@ +package org.dhis2.fhir.adapter.fhir.converter.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 org.dhis2.fhir.adapter.converter.ConvertedValueTypes; +import org.dhis2.fhir.adapter.fhir.converter.AbstractPrimitiveTypeDateToDateStringConverter; +import org.dhis2.fhir.adapter.model.ValueType; +import org.hl7.fhir.r4.model.BaseDateTimeType; +import org.springframework.stereotype.Component; + +/** + * FHIR version R4 implementation of {@link AbstractPrimitiveTypeDateToDateStringConverter}. + * + * @author volsch + */ +@Component +@ConvertedValueTypes( types = ValueType.DATE ) +public class R4BaseDateTimeTypeToDateStringConverter extends AbstractPrimitiveTypeDateToDateStringConverter +{ + public R4BaseDateTimeTypeToDateStringConverter() + { + super( BaseDateTimeType.class ); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4BaseDateTimeTypeToZonedDateTimeConverter.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4BaseDateTimeTypeToZonedDateTimeConverter.java new file mode 100644 index 00000000..88c17915 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4BaseDateTimeTypeToZonedDateTimeConverter.java @@ -0,0 +1,50 @@ +package org.dhis2.fhir.adapter.fhir.converter.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 org.dhis2.fhir.adapter.converter.ConvertedValueTypes; +import org.dhis2.fhir.adapter.fhir.converter.AbstractPrimitiveTypeDateToZonedDateTimeConverter; +import org.dhis2.fhir.adapter.model.ValueType; +import org.hl7.fhir.r4.model.BaseDateTimeType; +import org.springframework.stereotype.Component; + +/** + * FHIR version R4 implementation of {@link AbstractPrimitiveTypeDateToZonedDateTimeConverter}. + * + * @author volsch + */ +@Component +@ConvertedValueTypes( types = ValueType.DATETIME ) +public class R4BaseDateTimeTypeToZonedDateTimeConverter extends AbstractPrimitiveTypeDateToZonedDateTimeConverter +{ + public R4BaseDateTimeTypeToZonedDateTimeConverter() + { + super( BaseDateTimeType.class ); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4QuantityToStringConverter.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4QuantityToStringConverter.java new file mode 100644 index 00000000..16ead739 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4QuantityToStringConverter.java @@ -0,0 +1,62 @@ +package org.dhis2.fhir.adapter.fhir.converter.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 org.dhis2.fhir.adapter.converter.ConversionException; +import org.dhis2.fhir.adapter.converter.ConvertedValueTypes; +import org.dhis2.fhir.adapter.converter.TypedConverter; +import org.dhis2.fhir.adapter.model.ValueType; +import org.hl7.fhir.r4.model.Quantity; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * FHIR version R4 implementation of a FHIR quantity converter. + * + * @author volsch + */ +@Component +@ConvertedValueTypes( types = ValueType.TEXT ) +public class R4QuantityToStringConverter extends TypedConverter +{ + public R4QuantityToStringConverter() + { + super( Quantity.class, String.class ); + } + + @Nullable + @Override + public String doConvert( @Nonnull Quantity source ) throws ConversionException + { + final Number number = source.getValueElement().getValueAsNumber(); + return (number == null) ? null : number.toString(); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4StringToAdministrativeGenderConverter.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4StringToAdministrativeGenderConverter.java new file mode 100644 index 00000000..2dd347c7 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4StringToAdministrativeGenderConverter.java @@ -0,0 +1,73 @@ +package org.dhis2.fhir.adapter.fhir.converter.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 org.dhis2.fhir.adapter.converter.ConvertedValueTypes; +import org.dhis2.fhir.adapter.fhir.converter.AbstractStringToAdministrativeGenderConverter; +import org.dhis2.fhir.adapter.fhir.metadata.model.ConstantResolver; +import org.dhis2.fhir.adapter.model.ValueType; +import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * FHIR version R4 implementation of {@link AbstractStringToAdministrativeGenderConverter}. + * + * @author volsch + */ +@Component +@ConvertedValueTypes( types = ValueType.TEXT ) +public class R4StringToAdministrativeGenderConverter extends AbstractStringToAdministrativeGenderConverter +{ + public R4StringToAdministrativeGenderConverter( @Nonnull ConstantResolver constantResolver ) + { + super( AdministrativeGender.class, constantResolver ); + } + + @Nullable + @Override + protected AdministrativeGender getAdministrativeGender( @Nullable Gender gender ) + { + if ( gender == null ) + { + return AdministrativeGender.NULL; + } + switch ( gender ) + { + case FEMALE: + return AdministrativeGender.FEMALE; + case MALE: + return AdministrativeGender.MALE; + default: + throw new AssertionError( "Unhandled gender: " + gender ); + } + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/r4/R4FhirRepositoryResourceUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/r4/R4FhirRepositoryResourceUtils.java new file mode 100644 index 00000000..108b2862 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/r4/R4FhirRepositoryResourceUtils.java @@ -0,0 +1,82 @@ +package org.dhis2.fhir.adapter.fhir.repository.impl.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 org.dhis2.fhir.adapter.fhir.metadata.repository.FhirServerSystemRepository; +import org.dhis2.fhir.adapter.fhir.repository.FhirResourceTransformationException; +import org.dhis2.fhir.adapter.fhir.repository.impl.AbstractFhirRepositoryResourceUtils; +import org.dhis2.fhir.adapter.util.NameUtils; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.ICompositeType; +import org.hl7.fhir.r4.model.Identifier; +import org.hl7.fhir.r4.model.ResourceFactory; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.UUID; + +/** + * R4 specific implementation of {@link AbstractFhirRepositoryResourceUtils}. + * + * @author volsch + */ +public class R4FhirRepositoryResourceUtils extends AbstractFhirRepositoryResourceUtils +{ + public R4FhirRepositoryResourceUtils( @Nonnull UUID fhirServerId, @Nonnull FhirServerSystemRepository fhirServerSystemRepository ) + { + super( fhirServerId, fhirServerSystemRepository ); + } + + @Nonnull + @Override + public IBaseResource createResource( @Nonnull Object resourceType ) + { + try + { + return ResourceFactory.createResource( NameUtils.toClassName( resourceType ) ); + } + catch ( FHIRException e ) + { + throw new FhirResourceTransformationException( "Unknown FHIR resource type: " + resourceType, e ); + } + } + + @Nullable + @Override + public String getIdentifierValue( @Nullable Collection identifiers, @Nullable String system ) + { + if ( (identifiers == null) || (system == null) ) + { + return null; + } + return identifiers.stream().map( i -> (Identifier) i ).filter( i -> system.equals( i.getSystem() ) ).findFirst().map( Identifier::getValue ).orElse( null ); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/r4/R4FhirResourceRepositorySupport.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/r4/R4FhirResourceRepositorySupport.java new file mode 100644 index 00000000..4e24533c --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/r4/R4FhirResourceRepositorySupport.java @@ -0,0 +1,127 @@ +package org.dhis2.fhir.adapter.fhir.repository.impl.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 org.dhis2.fhir.adapter.fhir.metadata.model.FhirServerResource; +import org.dhis2.fhir.adapter.fhir.metadata.model.SubscriptionType; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirServerSystemRepository; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.repository.impl.AbstractFhirRepositoryResourceUtils; +import org.dhis2.fhir.adapter.fhir.repository.impl.AbstractFhirResourceRepositorySupport; +import org.hl7.fhir.instance.model.api.IAnyResource; +import org.hl7.fhir.instance.model.api.IBaseBundle; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Resource; +import org.hl7.fhir.r4.model.Subscription; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +/** + * Implementation of {@link AbstractFhirResourceRepositorySupport} for R4. + * + * @author volsch + */ +@Component +public class R4FhirResourceRepositorySupport extends AbstractFhirResourceRepositorySupport +{ + private final FhirServerSystemRepository fhirServerSystemRepository; + + public R4FhirResourceRepositorySupport( @Nonnull FhirServerSystemRepository fhirServerSystemRepository ) + { + this.fhirServerSystemRepository = fhirServerSystemRepository; + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nonnull + @Override + protected AbstractFhirRepositoryResourceUtils createFhirRepositoryResourceUtils( @Nonnull UUID fhirServerId ) + { + return new R4FhirRepositoryResourceUtils( fhirServerId, fhirServerSystemRepository ); + } + + @Nonnull + @Override + protected IAnyResource createFhirSubscription( @Nonnull FhirServerResource fhirServerResource ) + { + final Subscription.SubscriptionChannelComponent channelComponent = new Subscription.SubscriptionChannelComponent(); + channelComponent.setType( Subscription.SubscriptionChannelType.RESTHOOK ); + channelComponent.setEndpoint( createWebHookUrl( fhirServerResource ) ); + channelComponent.addHeader( "Authorization: " + fhirServerResource.getFhirServer().getAdapterEndpoint().getAuthorizationHeader() ); + if ( fhirServerResource.getFhirServer().getAdapterEndpoint().getSubscriptionType() == SubscriptionType.REST_HOOK_WITH_JSON_PAYLOAD ) + { + channelComponent.setPayload( "application/fhir+json" ); + } + + final Subscription subscription = new Subscription(); + subscription.setStatus( Subscription.SubscriptionStatus.REQUESTED ); + subscription.setCriteria( fhirServerResource.getFhirResourceType().getResourceTypeName() + "?" ); + subscription.setChannel( channelComponent ); + return subscription; + } + + @Nonnull + @Override + protected Class getBundleClass() + { + return Bundle.class; + } + + @Nullable + @Override + protected IBaseResource getFirstResource( @Nonnull IBaseBundle bundle ) + { + final Bundle b = (Bundle) bundle; + return (b.isEmpty() || b.getEntry().isEmpty()) ? null : b.getEntryFirstRep().getResource(); + } + + @Nonnull + @Override + protected IBaseBundle createBundle( @Nonnull List resources ) + { + final Bundle bundle = new Bundle(); + resources.stream().map( r -> { + final Bundle.BundleEntryComponent component = new Bundle.BundleEntryComponent(); + component.setResource( (Resource) r ); + return component; + } ).forEach( bundle::addEntry ); + return bundle; + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/impl/r4/R4SubscriptionResourceItemRetrieverImpl.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/impl/r4/R4SubscriptionResourceItemRetrieverImpl.java new file mode 100644 index 00000000..9998c16e --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/server/impl/r4/R4SubscriptionResourceItemRetrieverImpl.java @@ -0,0 +1,114 @@ +package org.dhis2.fhir.adapter.fhir.server.impl.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.context.FhirContext; +import ca.uhn.fhir.rest.client.api.IGenericClient; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.server.impl.AbstractSubscriptionResourceItemRetriever; +import org.hl7.fhir.instance.model.api.IAnyResource; +import org.hl7.fhir.instance.model.api.IBaseBundle; +import org.hl7.fhir.r4.model.Bundle; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Implementation of {@link AbstractSubscriptionResourceItemRetriever} for R4. + * + * @author volsch + */ +@Component +public class R4SubscriptionResourceItemRetrieverImpl extends AbstractSubscriptionResourceItemRetriever +{ + public R4SubscriptionResourceItemRetrieverImpl( @Nonnull @Qualifier( "fhirContextR4" ) FhirContext fhirContext ) + { + super( fhirContext ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nonnull + @Override + protected Class getBundleClass() + { + return Bundle.class; + } + + @Nonnull + @Override + protected List getResourceEntries( @Nonnull IBaseBundle bundle ) + { + final Bundle b = (Bundle) bundle; + return b.getEntry().stream().map( Bundle.BundleEntryComponent::getResource ).collect( Collectors.toList() ); + } + + @Nullable + @Override + protected Long getBundleTotalCount( @Nonnull IBaseBundle bundle ) + { + final Bundle b = (Bundle) bundle; + return b.hasTotal() ? (long) b.getTotal() : null; + } + + @Nullable + @Override + protected IBaseBundle loadNextPage( @Nonnull IGenericClient client, @Nonnull IBaseBundle bundle ) + { + final Bundle b = (Bundle) bundle; + final Bundle.BundleLinkComponent link = b.getLink( Bundle.LINK_NEXT ); + return ((link != null) && !link.isEmpty()) ? client.loadPage().next( bundle ).execute() : null; + } + + @Nullable + @Override + protected IBaseBundle loadPreviousPage( @Nonnull IGenericClient client, @Nonnull IBaseBundle bundle ) + { + final Bundle b = (Bundle) bundle; + final Bundle.BundleLinkComponent link = b.getLink( Bundle.LINK_PREV ); + return ((link != null) && !link.isEmpty()) ? client.loadPage().previous( bundle ).execute() : null; + } + + @Override + protected boolean isEmpty( @Nullable IBaseBundle bundle ) + { + final Bundle b = (Bundle) bundle; + return (b == null) || b.getEntry().isEmpty(); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4AdministrativeGenderDhisToFhirTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4AdministrativeGenderDhisToFhirTransformerUtils.java new file mode 100644 index 00000000..d7a67fcc --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4AdministrativeGenderDhisToFhirTransformerUtils.java @@ -0,0 +1,69 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.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 org.dhis2.fhir.adapter.dhis.converter.ValueConverter; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.AbstractAdministrativeGenderDhisToFhirTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.r4.model.Enumerations; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import java.util.Set; + +/** + * DTSU3 specific implementation of {@link AbstractAdministrativeGenderDhisToFhirTransformerUtils}. + * + * @author volsch + */ +@Scriptable +@Component +public class R4AdministrativeGenderDhisToFhirTransformerUtils extends AbstractAdministrativeGenderDhisToFhirTransformerUtils +{ + public R4AdministrativeGenderDhisToFhirTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, @Nonnull ValueConverter valueConverter ) + { + super( scriptExecutionContext, valueConverter ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nonnull + @Override + protected Class getAdministrativeGenderClass() + { + return Enumerations.AdministrativeGender.class; + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4CodeDhisToFhirTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4CodeDhisToFhirTransformerUtils.java new file mode 100644 index 00000000..ccd4fc26 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4CodeDhisToFhirTransformerUtils.java @@ -0,0 +1,79 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.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 org.dhis2.fhir.adapter.fhir.metadata.repository.SystemCodeRepository; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.model.SystemCodeValue; +import org.dhis2.fhir.adapter.fhir.model.SystemCodeValues; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.AbstractCodeDhisToFhirTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.instance.model.api.ICompositeType; +import org.hl7.fhir.r4.model.CodeableConcept; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import java.util.Set; + +/** + * R4 specific implementation of {@link AbstractCodeDhisToFhirTransformerUtils}. + * + * @author volsch + */ +@Scriptable +@Component +public class R4CodeDhisToFhirTransformerUtils extends AbstractCodeDhisToFhirTransformerUtils +{ + public R4CodeDhisToFhirTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, @Nonnull SystemCodeRepository systemCodeRepository ) + { + super( scriptExecutionContext, systemCodeRepository ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nonnull + @Override + protected ICompositeType createCodeableConcept( @Nonnull SystemCodeValues systemCodeValues ) + { + final CodeableConcept codeableConcept = new CodeableConcept(); + codeableConcept.setText( systemCodeValues.getText() ); + for ( final SystemCodeValue scv : systemCodeValues.getSystemCodeValues() ) + { + codeableConcept.addCoding().setSystem( scv.getSystem() ).setCode( scv.getCode() ) + .setDisplay( scv.getDisplayName() ); + } + return codeableConcept; + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4DateTimeDhisToFhirTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4DateTimeDhisToFhirTransformerUtils.java new file mode 100644 index 00000000..656c5c5d --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4DateTimeDhisToFhirTransformerUtils.java @@ -0,0 +1,136 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.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.model.api.TemporalPrecisionEnum; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.AbstractDateTimeDhisToFhirTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.dhis2.fhir.adapter.util.CastUtils; +import org.hl7.fhir.instance.model.api.IPrimitiveType; +import org.hl7.fhir.r4.model.BaseDateTimeType; +import org.hl7.fhir.r4.model.DateTimeType; +import org.hl7.fhir.r4.model.DateType; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.temporal.Temporal; +import java.util.Date; +import java.util.Set; + +/** + * FHIR version R4 implementation of {@link AbstractDateTimeDhisToFhirTransformerUtils}. + * + * @author volsch + */ +@Component +@Scriptable +public class R4DateTimeDhisToFhirTransformerUtils extends AbstractDateTimeDhisToFhirTransformerUtils +{ + protected final ZoneId zoneId = ZoneId.systemDefault(); + + public R4DateTimeDhisToFhirTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) + { + super( scriptExecutionContext ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nullable + @Override + public IPrimitiveType getPreciseDateElement( @Nullable Object dateTime ) + { + final LocalDate date = castDate( dateTime ); + if ( date == null ) + { + return null; + } + return new DateType( Date.from( date.atStartOfDay( zoneId ).toInstant() ), TemporalPrecisionEnum.DAY ); + } + + @Nullable + @Override + public IPrimitiveType getDateTimeElement( @Nullable Object dateTime ) + { + final LocalDateTime date = castDateTime( dateTime ); + if ( date == null ) + { + return null; + } + return new DateTimeType( Date.from( date.atZone( zoneId ).toInstant() ), TemporalPrecisionEnum.MILLI ); + } + + @Nullable + @Override + public IPrimitiveType getDayDateTimeElement( @Nullable Object dateTime ) + { + final LocalDateTime date = castDateTime( dateTime ); + if ( date == null ) + { + return null; + } + return new DateTimeType( Date.from( date.atZone( zoneId ).toInstant() ), TemporalPrecisionEnum.DAY ); + } + + @Nullable + protected LocalDate castDate( @Nullable Object date ) + { + return CastUtils.cast( date, + BaseDateTimeType.class, d -> { + final Date result = hasDayPrecision( d ) ? d.getValue() : null; + return (result == null) ? null : LocalDate.from( result.toInstant().atZone( zoneId ) ); + }, + Date.class, d -> LocalDate.from( d.toInstant().atZone( zoneId ) ), + Temporal.class, LocalDate::from ); + } + + @Nullable + protected LocalDateTime castDateTime( @Nullable Object date ) + { + return CastUtils.cast( date, + BaseDateTimeType.class, d -> LocalDateTime.ofInstant( d.getValue().toInstant(), zoneId ), + Date.class, d -> LocalDateTime.from( d.toInstant().atZone( zoneId ) ), + Temporal.class, LocalDateTime::from ); + } + + protected boolean hasDayPrecision( @Nonnull IPrimitiveType dateTime ) + { + return (((BaseDateTimeType) dateTime).getPrecision().ordinal() >= TemporalPrecisionEnum.DAY.ordinal()); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4EncounterDhisToFhirTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4EncounterDhisToFhirTransformerUtils.java new file mode 100644 index 00000000..a1c34da0 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4EncounterDhisToFhirTransformerUtils.java @@ -0,0 +1,79 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.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 org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.TransformerException; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.AbstractEncounterDhisToFhirTransformerUtils; +import org.dhis2.fhir.adapter.fhir.transform.scripted.TransformerScriptException; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r4.model.Encounter; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Set; + +/** + * R4 specific implementation of {@link AbstractEncounterDhisToFhirTransformerUtils}. + * + * @author volsch + */ +@Scriptable +@Component +public class R4EncounterDhisToFhirTransformerUtils extends AbstractEncounterDhisToFhirTransformerUtils +{ + public R4EncounterDhisToFhirTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) + { + super( scriptExecutionContext ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nullable + @Override + public Enum getEncounterStatus( @Nonnull String code ) throws TransformerException + { + try + { + return Encounter.EncounterStatus.fromCode( code ); + } + catch ( FHIRException e ) + { + throw new TransformerScriptException( "Unknown encounter status code: " + code, e ); + } + } +} diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/impl/dstu3/Dstu3HierarchicallyFhirResourceRepositoryImpl.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4FhirClientDhisToFhirTransformerUtils.java similarity index 58% rename from fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/impl/dstu3/Dstu3HierarchicallyFhirResourceRepositoryImpl.java rename to fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4FhirClientDhisToFhirTransformerUtils.java index 83ed2ecb..b11dae2e 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/server/impl/dstu3/Dstu3HierarchicallyFhirResourceRepositoryImpl.java +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4FhirClientDhisToFhirTransformerUtils.java @@ -1,7 +1,7 @@ -package org.dhis2.fhir.adapter.fhir.server.impl.dstu3; +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.r4; /* - * 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 @@ -28,40 +28,38 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import ca.uhn.fhir.context.FhirContext; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirServerRepository; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; import org.dhis2.fhir.adapter.fhir.repository.FhirResourceRepository; -import org.dhis2.fhir.adapter.fhir.repository.impl.AbstractHierarchicallyFhirResourceRepositoryImpl; -import org.hl7.fhir.dstu3.model.Bundle; -import org.hl7.fhir.dstu3.model.Resource; -import org.hl7.fhir.instance.model.api.IBaseBundle; -import org.hl7.fhir.instance.model.api.IBaseResource; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.AbstractFhirClientDhisToFhirTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import javax.annotation.Nonnull; -import java.util.List; +import java.util.Set; /** - * Implementation of {@link AbstractHierarchicallyFhirResourceRepositoryImpl} for DSTU3. + * FHIR version R4 implementation of {@link AbstractFhirClientDhisToFhirTransformerUtils}. * * @author volsch */ @Component -public class Dstu3HierarchicallyFhirResourceRepositoryImpl extends AbstractHierarchicallyFhirResourceRepositoryImpl +@Scriptable +public class R4FhirClientDhisToFhirTransformerUtils extends AbstractFhirClientDhisToFhirTransformerUtils { - public Dstu3HierarchicallyFhirResourceRepositoryImpl( @Nonnull FhirResourceRepository fhirResourceRepository ) + public R4FhirClientDhisToFhirTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, @Nonnull @Qualifier( "fhirContextR4" ) FhirContext fhirContext, + @Nonnull FhirServerRepository subscriptionRepository, @Nonnull FhirResourceRepository fhirResourceRepository ) { - super( fhirResourceRepository ); + super( scriptExecutionContext, fhirContext, subscriptionRepository, fhirResourceRepository ); } @Nonnull @Override - protected IBaseBundle createBundle( @Nonnull List resources ) + public Set getFhirVersions() { - final Bundle bundle = new Bundle(); - resources.stream().map( r -> { - final Bundle.BundleEntryComponent component = new Bundle.BundleEntryComponent(); - component.setResource( (Resource) r ); - return component; - } ).forEach( bundle::addEntry ); - return bundle; + return FhirVersion.R4_ONLY; } } diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4FhirResourceDhisToFhirTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4FhirResourceDhisToFhirTransformerUtils.java new file mode 100644 index 00000000..bec9e366 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4FhirResourceDhisToFhirTransformerUtils.java @@ -0,0 +1,139 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.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 org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.repository.FhirRepositoryException; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.AbstractFhirResourceDhisToFhirTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.dhis2.fhir.adapter.util.NameUtils; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.instance.model.api.IBase; +import org.hl7.fhir.instance.model.api.IBaseElement; +import org.hl7.fhir.instance.model.api.IBaseReference; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.ICompositeType; +import org.hl7.fhir.instance.model.api.IPrimitiveType; +import org.hl7.fhir.r4.model.Base; +import org.hl7.fhir.r4.model.CodeableConcept; +import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.Resource; +import org.hl7.fhir.r4.model.ResourceFactory; +import org.hl7.fhir.r4.model.StringType; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Set; + +/** + * R4 specific implementation of {@link AbstractFhirResourceDhisToFhirTransformerUtils}. + * + * @author volsch + */ +@Scriptable +@Component +public class R4FhirResourceDhisToFhirTransformerUtils extends AbstractFhirResourceDhisToFhirTransformerUtils +{ + public R4FhirResourceDhisToFhirTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) + { + super( scriptExecutionContext ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nonnull + @Override + public IBaseResource createResource( @Nonnull String resourceType ) + { + try + { + return ResourceFactory.createResource( NameUtils.toClassName( resourceType ) ); + } + catch ( FHIRException e ) + { + throw new FhirRepositoryException( "Unknown FHIR resource type: " + resourceType, e ); + } + } + + @Nonnull + @Override + public ICompositeType createCodeableConcept() + { + return new CodeableConcept(); + } + + @Nonnull + @Override + public IBaseReference createReference( @Nonnull IBaseResource resource ) + { + if ( resource.getIdElement().isEmpty() || resource.getIdElement().isLocal() ) + { + return new Reference( (Resource) resource ); + } + return new Reference( resource.getIdElement().toUnqualifiedVersionless() ); + } + + @Nonnull + @Override + public IBaseElement createType( @Nonnull String fhirType ) + { + try + { + return ResourceFactory.createType( fhirType ); + } + catch ( FHIRException e ) + { + throw new FhirRepositoryException( "Unknown FHIR type: " + fhirType, e ); + } + } + + @Override + public boolean containsString( @Nonnull List> stringList, @Nullable String value ) + { + if ( value == null ) + { + return false; + } + return stringList.contains( new StringType( value ) ); + } + + @Override + public boolean equalsDeep( @Nonnull IBase base1, @Nonnull IBase base2 ) + { + return ((Base) base1).equalsDeep( (Base) base2 ); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4GeoDhisToFhirTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4GeoDhisToFhirTransformerUtils.java new file mode 100644 index 00000000..4b80511f --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4GeoDhisToFhirTransformerUtils.java @@ -0,0 +1,99 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.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.model.api.IElement; +import org.dhis2.fhir.adapter.dhis.converter.ValueConverter; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.TransformerException; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.AbstractGeoDhisToFhirTransformerUtils; +import org.dhis2.fhir.adapter.geo.Location; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.instance.model.api.IBaseBackboneElement; +import org.hl7.fhir.r4.model.DecimalType; +import org.hl7.fhir.r4.model.Element; +import org.hl7.fhir.r4.model.Extension; +import org.hl7.fhir.r4.model.Location.LocationPositionComponent; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Set; + +/** + * FHIR version R4 implementation of {@link AbstractGeoDhisToFhirTransformerUtils}. + * + * @author volsch + */ +@Component +@Scriptable +public class R4GeoDhisToFhirTransformerUtils extends AbstractGeoDhisToFhirTransformerUtils +{ + public R4GeoDhisToFhirTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, @Nonnull ValueConverter valueConverter ) + { + super( scriptExecutionContext ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Override + public void updateAddressLocation( @Nonnull IElement element, @Nullable Location location ) throws TransformerException + { + final Element e = (Element) element; + e.getExtension().removeIf( i -> i.hasExtension( GEO_LOCATION_URI ) ); + if ( location != null ) + { + e.addExtension().setUrl( GEO_LOCATION_URI ) + .addExtension( new Extension().setUrl( LATITUDE_URL ) + .setValue( new DecimalType( location.getLatitude() ) ) ) + .addExtension( new Extension().setUrl( LONGITUDE_URL ) + .setValue( new DecimalType( location.getLongitude() ) ) ); + } + } + + @Nullable + @Override + public IBaseBackboneElement createPosition( @Nullable Location location ) + { + if ( location == null ) + { + return null; + } + final LocationPositionComponent lpc = new LocationPositionComponent(); + lpc.setLatitude( location.getLatitude() ); + lpc.setLongitude( location.getLongitude() ); + return lpc; + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4HumanNameDhisToFhirTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4HumanNameDhisToFhirTransformerUtils.java new file mode 100644 index 00000000..745bafd1 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4HumanNameDhisToFhirTransformerUtils.java @@ -0,0 +1,80 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.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 org.apache.commons.lang3.StringUtils; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.AbstractHumanNameDhisToFhirTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.instance.model.api.ICompositeType; +import org.hl7.fhir.r4.model.HumanName; +import org.hl7.fhir.r4.model.StringType; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * R4 specific implementation of {@link AbstractHumanNameDhisToFhirTransformerUtils}. + * + * @author volsch + */ +@Scriptable +@Component +public class R4HumanNameDhisToFhirTransformerUtils extends AbstractHumanNameDhisToFhirTransformerUtils +{ + public R4HumanNameDhisToFhirTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) + { + super( scriptExecutionContext ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Override + public void updateGiven( @Nonnull ICompositeType humanName, @Nullable String firstName ) + { + if ( StringUtils.isBlank( firstName ) ) + { + ((HumanName) humanName).setGiven( null ); + } + else + { + ((HumanName) humanName).setGiven( Arrays.stream( firstName.split( " " ) ).map( StringType::new ).collect( Collectors.toList() ) ); + } + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4IdentifierDhisToFhirTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4IdentifierDhisToFhirTransformerUtils.java new file mode 100644 index 00000000..9262e84b --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4IdentifierDhisToFhirTransformerUtils.java @@ -0,0 +1,100 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.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 org.apache.commons.lang3.StringUtils; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.FatalTransformerException; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.AbstractIdentifierDhisToFhirTransformerUtils; +import org.dhis2.fhir.adapter.fhir.transform.util.FhirIdentifierUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.Identifier; +import org.springframework.stereotype.Component; +import org.springframework.util.ReflectionUtils; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +/** + * R4 specific implementation of {@link AbstractIdentifierDhisToFhirTransformerUtils}. + * + * @author volsch + */ +@Scriptable +@Component +public class R4IdentifierDhisToFhirTransformerUtils extends AbstractIdentifierDhisToFhirTransformerUtils +{ + public R4IdentifierDhisToFhirTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, @Nonnull FhirIdentifierUtils fhirIdentifierUtils ) + { + super( scriptExecutionContext, fhirIdentifierUtils ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Override + protected void addOrUpdateIdentifier( @Nonnull IBaseResource resource, @Nonnull Method identifierMethod, @Nullable String system, @Nonnull String value, @Nullable String text, boolean secondary ) + { + @SuppressWarnings( "unchecked" ) final List identifiers = (List) ReflectionUtils.invokeMethod( identifierMethod, resource ); + if ( identifiers == null ) + { + throw new FatalTransformerException( "FHIR resource " + resource.getClass().getSimpleName() + " returned null for identifiers." ); + } + + final Optional identifier = identifiers.stream().filter( i -> Objects.equals( system, i.getSystem() ) ).findFirst(); + if ( identifier.isPresent() ) + { + identifier.get().setValue( value ); + } + else + { + final Identifier i = new Identifier().setSystem( system ).setValue( value ); + if ( StringUtils.isNotBlank( text ) ) + { + i.getType().setText( text ); + } + if ( secondary ) + { + i.setUse( Identifier.IdentifierUse.SECONDARY ); + } + identifiers.add( i ); + } + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4LocationDhisToFhirTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4LocationDhisToFhirTransformerUtils.java new file mode 100644 index 00000000..c1d05cbb --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4LocationDhisToFhirTransformerUtils.java @@ -0,0 +1,79 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.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 org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.TransformerException; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.AbstractLocationDhisToFhirTransformerUtils; +import org.dhis2.fhir.adapter.fhir.transform.scripted.TransformerScriptException; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r4.model.Location; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Set; + +/** + * R4 specific implementation of {@link AbstractLocationDhisToFhirTransformerUtils}. + * + * @author volsch + */ +@Scriptable +@Component +public class R4LocationDhisToFhirTransformerUtils extends AbstractLocationDhisToFhirTransformerUtils +{ + public R4LocationDhisToFhirTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) + { + super( scriptExecutionContext ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nullable + @Override + public Enum getLocationStatus( @Nonnull String code ) throws TransformerException + { + try + { + return Location.LocationStatus.fromCode( code ); + } + catch ( FHIRException e ) + { + throw new TransformerScriptException( "Unknown location status code: " + code, e ); + } + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4ObservationDhisToFhirTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4ObservationDhisToFhirTransformerUtils.java new file mode 100644 index 00000000..cd4decad --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4ObservationDhisToFhirTransformerUtils.java @@ -0,0 +1,79 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.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 org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.TransformerException; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.AbstractObservationDhisToFhirTransformerUtils; +import org.dhis2.fhir.adapter.fhir.transform.scripted.TransformerScriptException; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r4.model.Observation; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Set; + +/** + * R4 specific implementation of {@link AbstractObservationDhisToFhirTransformerUtils}. + * + * @author volsch + */ +@Scriptable +@Component +public class R4ObservationDhisToFhirTransformerUtils extends AbstractObservationDhisToFhirTransformerUtils +{ + public R4ObservationDhisToFhirTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) + { + super( scriptExecutionContext ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nullable + @Override + public Enum getObservationStatus( @Nonnull String code ) throws TransformerException + { + try + { + return Observation.ObservationStatus.fromCode( code ); + } + catch ( FHIRException e ) + { + throw new TransformerScriptException( "Unknown observation status code: " + code, e ); + } + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4AddressFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4AddressFhirToDhisTransformerUtils.java new file mode 100644 index 00000000..22452282 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4AddressFhirToDhisTransformerUtils.java @@ -0,0 +1,206 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.apache.commons.lang3.StringUtils; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.AbstractAddressFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.TransformerComparatorUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.instance.model.api.ICompositeType; +import org.hl7.fhir.r4.model.Address; +import org.hl7.fhir.r4.model.PrimitiveType; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * FHIR version R4 implementation of {@link AbstractAddressFhirToDhisTransformerUtils}. + * + * @author volsch + */ +@Component +@Scriptable +public class R4AddressFhirToDhisTransformerUtils extends AbstractAddressFhirToDhisTransformerUtils +{ + private final R4DateTimeFhirToDhisTransformerUtils dateTimeTransformerUtils; + + public R4AddressFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, @Nonnull R4DateTimeFhirToDhisTransformerUtils dateTimeTransformerUtils ) + { + super( scriptExecutionContext ); + this.dateTimeTransformerUtils = dateTimeTransformerUtils; + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nullable + @Override + public ICompositeType getPrimaryAddress( @Nonnull List addresses ) + { + return getOptionalPrimaryAddress( addresses ).orElse( new Address() ); + } + + @Nullable + @Override + public String getSingleLine( @Nullable ICompositeType address, @Nonnull String delimiter ) + { + final Address convertedAddress = (Address) address; + if ( (address == null) || convertedAddress.getLine().isEmpty() ) + { + return null; + } + return convertedAddress.getLine().stream().map( PrimitiveType::getValue ).collect( Collectors.joining( delimiter ) ); + } + + @Nullable + @Override + public String getConstructedText( @Nullable ICompositeType address, @Nonnull String delimiter ) + { + final Address convertedAddress = (Address) address; + if ( address == null ) + { + return null; + } + + final StringBuilder sb = new StringBuilder(); + convertedAddress.getLine().stream().filter( l -> (l != null) && StringUtils.isNotBlank( l.getValue() ) ) + .forEach( l -> sb.append( delimiter ).append( l.getValue() ) ); + if ( StringUtils.isNotBlank( convertedAddress.getPostalCode() ) && StringUtils.isNotBlank( convertedAddress.getCity() ) ) + { + sb.append( delimiter ).append( convertedAddress.getPostalCode() ).append( ' ' ).append( convertedAddress.getCity() ); + } + else if ( StringUtils.isNotBlank( convertedAddress.getPostalCode() ) ) + { + sb.append( delimiter ).append( convertedAddress.getPostalCode() ); + } + else if ( StringUtils.isNotBlank( convertedAddress.getCity() ) ) + { + sb.append( delimiter ).append( convertedAddress.getCity() ); + } + if ( StringUtils.isNotBlank( convertedAddress.getState() ) ) + { + sb.append( delimiter ).append( convertedAddress.getState() ); + } + if ( sb.length() == 0 ) + { + return convertedAddress.getText(); + } + return sb.substring( delimiter.length() ); + } + + @Nullable + @Override + public String getText( @Nullable ICompositeType address ) + { + final Address convertedAddress = (Address) address; + return (convertedAddress == null) ? null : convertedAddress.getText(); + } + + @Nonnull + protected Optional
getOptionalPrimaryAddress( @Nullable List addresses ) + { + if ( (addresses == null) || addresses.isEmpty() ) + { + return Optional.empty(); + } + if ( addresses.size() == 1 ) + { + return Optional.of( (Address) addresses.get( 0 ) ); + } + return addresses.stream().map( Address.class::cast ) + .filter( a -> dateTimeTransformerUtils.isValidNow( a.getPeriod() ) ).min( new AddressComparator() ); + } + + protected static class AddressComparator implements Comparator
+ { + @Override + public int compare( Address o1, Address o2 ) + { + int value = getAddressUseValue( o1.getUse() ) - getAddressUseValue( o2.getUse() ); + if ( value != 0 ) + { + return value; + } + value = getAddressTypeValue( o1.getType() ) - getAddressTypeValue( o2.getType() ); + if ( value != 0 ) + { + return value; + } + return comparatorValue( o1 ).compareTo( comparatorValue( o2 ) ); + } + + private int getAddressUseValue( @Nullable Address.AddressUse au ) + { + if ( au == Address.AddressUse.OLD ) + { + return 8; + } + else if ( au == Address.AddressUse.WORK ) + { + return 6; + } + else if ( au == Address.AddressUse.TEMP ) + { + return 5; + } + return 0; + } + + private int getAddressTypeValue( @Nullable Address.AddressType at ) + { + if ( at == Address.AddressType.POSTAL ) + { + return 8; + } + if ( at == Address.AddressType.BOTH ) + { + return 2; + } + return 0; + } + + @Nonnull + private String comparatorValue( @Nonnull Address a ) + { + return TransformerComparatorUtils.comparatorValue( a.getText(), a.getLine(), a.getPostalCode(), a.getCity(), a.getState(), a.getCountry() ); + } + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4CodeFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4CodeFhirToDhisTransformerUtils.java new file mode 100644 index 00000000..0ab65746 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4CodeFhirToDhisTransformerUtils.java @@ -0,0 +1,183 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 com.google.common.collect.Sets; +import org.dhis2.fhir.adapter.fhir.metadata.model.ScriptArgUtils; +import org.dhis2.fhir.adapter.fhir.metadata.model.SystemCode; +import org.dhis2.fhir.adapter.fhir.metadata.repository.CodeRepository; +import org.dhis2.fhir.adapter.fhir.metadata.repository.SystemCodeRepository; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.model.SystemCodeValue; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.AbstractCodeFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.instance.model.api.ICompositeType; +import org.hl7.fhir.instance.model.api.IDomainResource; +import org.hl7.fhir.r4.model.CodeableConcept; +import org.hl7.fhir.r4.model.Coding; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * FHIR version R4 implementation of {@link AbstractCodeFhirToDhisTransformerUtils}. + * + * @author volsch + */ +@Component +@Scriptable +public class R4CodeFhirToDhisTransformerUtils extends AbstractCodeFhirToDhisTransformerUtils +{ + private final Logger logger = LoggerFactory.getLogger( getClass() ); + + public R4CodeFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, + @Nonnull CodeRepository codeRepository, + @Nonnull SystemCodeRepository systemCodeRepository ) + { + super( scriptExecutionContext, codeRepository, systemCodeRepository ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nonnull + @Override + public List getSystemCodeValues( @Nullable ICompositeType codeableConcept ) + { + if ( codeableConcept == null ) + { + return Collections.emptyList(); + } + final List result = new ArrayList<>(); + for ( final Coding coding : ((CodeableConcept) codeableConcept).getCoding() ) + { + result.add( new SystemCodeValue( coding.getSystem(), coding.getCode() ) ); + } + return result; + } + + @Override + @Nullable + public String getCode( @Nullable ICompositeType codeableConcept, @Nullable String system ) + { + if ( system == null ) + { + throw new IllegalArgumentException( "System must be specified." ); + } + + if ( codeableConcept == null ) + { + return null; + } + for ( final Coding coding : ((CodeableConcept) codeableConcept).getCoding() ) + { + if ( system.equals( coding.getSystem() ) ) + { + return coding.getCode(); + } + } + return null; + } + + @Override + public boolean containsMappingCode( @Nullable ICompositeType codeableConcept, @Nullable Object mappingCodes ) + { + if ( mappingCodes == null ) + { + throw new IllegalArgumentException( "Codes must be specified." ); + } + + if ( (codeableConcept == null) || codeableConcept.isEmpty() ) + { + return false; + } + final List convertedCodes = ScriptArgUtils.extractStringArray( mappingCodes ); + if ( CollectionUtils.isEmpty( convertedCodes ) ) + { + return false; + } + + final Set checkedCodes = new HashSet<>(); + final Collection systemCodes = getSystemCodeRepository().findAllByCodes( convertedCodes ); + for ( final SystemCode systemCode : systemCodes ) + { + if ( containsCode( codeableConcept, systemCode.getSystem().getSystemUri(), systemCode.getSystemCode() ) ) + { + return true; + } + checkedCodes.add( systemCode.getCode().getCode() ); + } + if ( logger.isDebugEnabled() && (checkedCodes.size() < convertedCodes.size()) ) + { + logger.info( "Codes have not been defined: " + Sets.difference( new HashSet<>( convertedCodes ), checkedCodes ) ); + } + return false; + } + + @Override + public boolean containsCode( @Nullable ICompositeType codeableConcept, @Nullable String system, @Nonnull String code ) + { + if ( codeableConcept == null ) + { + return false; + } + return ((CodeableConcept) codeableConcept).getCoding().stream().anyMatch( + coding -> Objects.equals( system, coding.getSystem() ) && code.equals( coding.getCode() ) ); + } + + @Nullable + @Override + protected List getSystemCodeValues( @Nonnull IDomainResource domainResource, @Nonnull Method identifierMethod ) + { + final ICompositeType codeableConcept = (ICompositeType) ReflectionUtils.invokeMethod( identifierMethod, domainResource ); + if ( codeableConcept != null ) + { + return getSystemCodeValues( codeableConcept ); + } + return null; + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ContactPointFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ContactPointFhirToDhisTransformerUtils.java new file mode 100644 index 00000000..f9d64000 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ContactPointFhirToDhisTransformerUtils.java @@ -0,0 +1,121 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.AbstractContactPointFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.TransformerComparatorUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.instance.model.api.ICompositeType; +import org.hl7.fhir.r4.model.ContactPoint; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Comparator; +import java.util.List; +import java.util.Set; + +/** + * FHIR version R4 implementation of {@link AbstractContactPointFhirToDhisTransformerUtils}. + * + * @author volsch + */ +@Component +@Scriptable +public class R4ContactPointFhirToDhisTransformerUtils extends AbstractContactPointFhirToDhisTransformerUtils +{ + private final R4DateTimeFhirToDhisTransformerUtils dateTimeTransformerUtils; + + public R4ContactPointFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, @Nonnull R4DateTimeFhirToDhisTransformerUtils dateTimeTransformerUtils ) + { + super( scriptExecutionContext ); + this.dateTimeTransformerUtils = dateTimeTransformerUtils; + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nullable + @Override + protected String getContactPointValue( @Nullable List contactPoints, @Nullable String code ) + { + if ( (contactPoints == null) || (code == null) ) + { + return null; + } + return contactPoints.stream().map( cp -> (ContactPoint) cp ) + .filter( cp -> cp.hasSystem() && code.equalsIgnoreCase( cp.getSystem().toCode() ) + && dateTimeTransformerUtils.isValidNow( cp.getPeriod() ) && cp.hasValue() ) + .min( new ContactPointComparator() ).map( ContactPoint::getValue ).orElse( null ); + } + + protected static class ContactPointComparator implements Comparator + { + @Override + public int compare( ContactPoint o1, ContactPoint o2 ) + { + int value = getContactPointUseValue( o1.getUse() ) - getContactPointUseValue( o2.getUse() ); + if ( value != 0 ) + { + return value; + } + value = o1.getRank() - o2.getRank(); + if ( value != 0 ) + { + return value; + } + return comparatorValue( o1 ).compareTo( comparatorValue( o2 ) ); + } + + private int getContactPointUseValue( @Nullable ContactPoint.ContactPointUse cpu ) + { + if ( cpu == ContactPoint.ContactPointUse.OLD ) + { + return 8; + } + else if ( cpu == ContactPoint.ContactPointUse.TEMP ) + { + return 5; + } + return 0; + } + + @Nonnull + private String comparatorValue( @Nonnull ContactPoint cp ) + { + return TransformerComparatorUtils.comparatorValue( cp.getValue() ); + } + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4DateTimeFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4DateTimeFhirToDhisTransformerUtils.java new file mode 100644 index 00000000..ec5bb2c0 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4DateTimeFhirToDhisTransformerUtils.java @@ -0,0 +1,111 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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.model.api.TemporalPrecisionEnum; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.AbstractDateTimeFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.dhis2.fhir.adapter.util.CastUtils; +import org.hl7.fhir.instance.model.api.ICompositeType; +import org.hl7.fhir.instance.model.api.IPrimitiveType; +import org.hl7.fhir.r4.model.BaseDateTimeType; +import org.hl7.fhir.r4.model.Period; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.temporal.Temporal; +import java.util.Date; +import java.util.Set; + +/** + * FHIR version R4 implementation of {@link AbstractDateTimeFhirToDhisTransformerUtils}. + * + * @author volsch + */ +@Component +@Scriptable +public class R4DateTimeFhirToDhisTransformerUtils extends AbstractDateTimeFhirToDhisTransformerUtils +{ + protected final ZoneId zoneId = ZoneId.systemDefault(); + + public R4DateTimeFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) + { + super( scriptExecutionContext ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Override + public boolean hasDayPrecision( @Nullable IPrimitiveType dateTime ) + { + if ( dateTime == null ) + { + // an unspecified date has at least day precision + return true; + } + return (((BaseDateTimeType) dateTime).getPrecision().ordinal() >= TemporalPrecisionEnum.DAY.ordinal()); + } + + @Override + public boolean isValidNow( @Nullable ICompositeType period ) + { + if ( period == null ) + { + return true; + } + + final Period p = (Period) period; + final Date now = new Date(); + // start will be ignored since there may be no further notification about that event + return (p.getEnd() == null) || !now.after( p.getEnd() ); + } + + @Override + @Nullable + protected LocalDate castDate( @Nonnull Object date ) + { + return CastUtils.cast( date, + BaseDateTimeType.class, d -> { + final Date result = getPreciseDate( d ); + return (result == null) ? null : LocalDate.from( result.toInstant().atZone( zoneId ) ); + }, + Date.class, d -> LocalDate.from( d.toInstant().atZone( zoneId ) ), + Temporal.class, LocalDate::from ); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4FhirClientFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4FhirClientFhirToDhisTransformerUtils.java new file mode 100644 index 00000000..892f7a09 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4FhirClientFhirToDhisTransformerUtils.java @@ -0,0 +1,104 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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.context.FhirContext; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirServerResourceRepository; +import org.dhis2.fhir.adapter.fhir.metadata.repository.SystemCodeRepository; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.AbstractFhirClientFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.instance.model.api.IBaseBundle; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; +import org.hl7.fhir.r4.model.Bundle.BundleLinkComponent; +import org.hl7.fhir.r4.model.Resource; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +@Component +@Scriptable +public class R4FhirClientFhirToDhisTransformerUtils extends AbstractFhirClientFhirToDhisTransformerUtils +{ + public R4FhirClientFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, @Nonnull @Qualifier( "fhirContextR4" ) FhirContext fhirContext, + @Nonnull FhirServerResourceRepository fhirServerResourceRepository, @Nonnull SystemCodeRepository systemCodeRepository ) + { + super( scriptExecutionContext, fhirContext, fhirServerResourceRepository, systemCodeRepository ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nonnull + @Override + protected Class getBundleClass() + { + return Bundle.class; + } + + @Override + protected boolean hasNextLink( @Nonnull IBaseBundle bundle ) + { + final BundleLinkComponent link = ((Bundle) bundle).getLink( Bundle.LINK_NEXT ); + return (link != null) && !link.isEmpty(); + } + + @Nullable + @Override + protected IBaseResource getFirstRep( @Nonnull IBaseBundle bundle ) + { + final Bundle b = (Bundle) bundle; + return (b.getEntry().isEmpty() ? null : b.getEntryFirstRep().getResource()); + } + + @Override + @Nonnull + protected List getEntries( @Nonnull IBaseBundle bundle ) + { + final Bundle b = (Bundle) bundle; + final List resources = new ArrayList<>(); + for ( final BundleEntryComponent entry : b.getEntry() ) + { + resources.add( entry.getResource() ); + } + return resources; + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4GeoFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4GeoFhirToDhisTransformerUtils.java new file mode 100644 index 00000000..35298292 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4GeoFhirToDhisTransformerUtils.java @@ -0,0 +1,106 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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.model.api.IElement; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +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.AbstractGeoFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.geo.Location; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.r4.model.DecimalType; +import org.hl7.fhir.r4.model.Element; +import org.hl7.fhir.r4.model.Extension; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Set; + +/** + * FHIR version R4 implementation of {@link AbstractGeoFhirToDhisTransformerUtils}. + * + * @author volsch + */ +@Component +@Scriptable +public class R4GeoFhirToDhisTransformerUtils extends AbstractGeoFhirToDhisTransformerUtils +{ + public R4GeoFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) + { + super( scriptExecutionContext ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Override + @Nullable + public Location getLocation( @Nonnull IElement element ) throws TransformerException + { + final Element e = (Element) element; + final List locationExtensions = e.getExtensionsByUrl( GEO_LOCATION_URI ); + if ( locationExtensions.isEmpty() ) + { + return null; + } + if ( locationExtensions.size() > 1 ) + { + throw new TransformerMappingException( "Element " + e.fhirType() + " contains " + locationExtensions.size() + " GEO locations." ); + } + final Extension locationExtension = locationExtensions.get( 0 ); + + return new Location( getLocationComponentValue( e, locationExtension, LONGITUDE_URL ), + getLocationComponentValue( e, locationExtension, LATITUDE_URL ) ); + } + + private double getLocationComponentValue( @Nonnull Element element, @Nonnull Extension locationExtension, @Nonnull String componentUrl ) + { + final List extensions = locationExtension.getExtensionsByUrl( componentUrl ); + if ( extensions.size() != 1 ) + { + throw new TransformerMappingException( "GEO location of element " + element.fhirType() + " does not include a valid " + componentUrl + " extension." ); + } + + final Extension valueExtension = extensions.get( 0 ); + if ( !(valueExtension.getValue() instanceof DecimalType) ) + { + throw new TransformerMappingException( "GEO location of element " + element.fhirType() + " does not include a valid " + componentUrl + " extension value." ); + } + + return ((DecimalType) valueExtension.getValue()).getValueAsNumber().doubleValue(); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4HumanNameFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4HumanNameFhirToDhisTransformerUtils.java new file mode 100644 index 00000000..3e112dc6 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4HumanNameFhirToDhisTransformerUtils.java @@ -0,0 +1,155 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.AbstractHumanNameFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.TransformerComparatorUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.instance.model.api.ICompositeType; +import org.hl7.fhir.r4.model.HumanName; +import org.hl7.fhir.r4.model.PrimitiveType; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * FHIR version R4 implementation of {@link AbstractHumanNameFhirToDhisTransformerUtils}. + * + * @author volsch + */ +@Component +@Scriptable +public class R4HumanNameFhirToDhisTransformerUtils extends AbstractHumanNameFhirToDhisTransformerUtils +{ + private final R4DateTimeFhirToDhisTransformerUtils dateTimeTransformerUtils; + + public R4HumanNameFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, @Nonnull R4DateTimeFhirToDhisTransformerUtils dateTimeTransformerUtils ) + { + super( scriptExecutionContext ); + this.dateTimeTransformerUtils = dateTimeTransformerUtils; + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Override + @Nullable + public String getSingleGiven( @Nullable ICompositeType humanName ) + { + if ( (humanName == null) || ((HumanName) humanName).getGiven().isEmpty() ) + { + return null; + } + return ((HumanName) humanName).getGiven().stream().map( PrimitiveType::getValue ).collect( Collectors.joining( DEFAULT_GIVEN_DELIMITER ) ); + } + + @Override + @Nullable + public HumanName getPrimaryName( @Nonnull List names ) + { + return getOptionalPrimaryName( names ).orElse( new HumanName() ); + } + + @Nonnull + protected Optional getOptionalPrimaryName( @Nullable List names ) + { + if ( (names == null) || names.isEmpty() ) + { + return Optional.empty(); + } + if ( names.size() == 1 ) + { + return Optional.of( (HumanName) names.get( 0 ) ); + } + return names.stream().map( HumanName.class::cast ) + .filter( hn -> dateTimeTransformerUtils.isValidNow( hn.getPeriod() ) ) + .min( new HumanNameComparator() ); + } + + protected static class HumanNameComparator implements Comparator + { + @Override + public int compare( HumanName o1, HumanName o2 ) + { + int value = getHumanNameUseValue( o1.getUse() ) - getHumanNameUseValue( o2.getUse() ); + if ( value != 0 ) + { + return value; + } + return comparatorValue( o1 ).compareTo( comparatorValue( o2 ) ); + } + + private int getHumanNameUseValue( @Nullable HumanName.NameUse nu ) + { + if ( nu == HumanName.NameUse.OLD ) + { + return 9; + } + else if ( nu == HumanName.NameUse.MAIDEN ) + { + return 8; + } + else if ( nu == HumanName.NameUse.TEMP ) + { + return 7; + } + else if ( nu == HumanName.NameUse.NICKNAME ) + { + return 6; + } + else if ( nu == HumanName.NameUse.ANONYMOUS ) + { + return 5; + } + else if ( nu == HumanName.NameUse.USUAL ) + { + return 4; + } + return 0; + } + + @Nonnull + private String comparatorValue( @Nonnull HumanName hu ) + { + return TransformerComparatorUtils.comparatorValue( hu.getText(), hu.getGiven(), hu.getFamily(), hu.getPrefix(), hu.getSuffix() ); + } + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4IdentifierFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4IdentifierFhirToDhisTransformerUtils.java new file mode 100644 index 00000000..98a0861a --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4IdentifierFhirToDhisTransformerUtils.java @@ -0,0 +1,81 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.AbstractIdentifierFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.ReferenceFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.fhir.transform.util.FhirIdentifierUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.instance.model.api.IDomainResource; +import org.hl7.fhir.r4.model.Identifier; +import org.springframework.stereotype.Component; +import org.springframework.util.ReflectionUtils; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * FHIR version R4 implementation of {@link AbstractIdentifierFhirToDhisTransformerUtils}. + * + * @author volsch + */ +@Component +@Scriptable +public class R4IdentifierFhirToDhisTransformerUtils extends AbstractIdentifierFhirToDhisTransformerUtils +{ + public R4IdentifierFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, @Nonnull FhirIdentifierUtils fhirIdentifierUtils, @Nonnull ReferenceFhirToDhisTransformerUtils referenceFhirToDhisTransformerUtils ) + { + super( scriptExecutionContext, fhirIdentifierUtils, referenceFhirToDhisTransformerUtils ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nullable + @Override + protected String getIdentifierValue( @Nonnull IDomainResource domainResource, @Nonnull Method identifierMethod, @Nullable String system ) + { + @SuppressWarnings( "unchecked" ) final List identifiers = (List) ReflectionUtils.invokeMethod( identifierMethod, domainResource ); + if ( identifiers != null ) + { + return identifiers.stream().filter( i -> Objects.equals( system, i.getSystem() ) ).findFirst().orElse( new Identifier() ).getValue(); + } + return null; + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ImmunizationFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ImmunizationFhirToDhisTransformerUtils.java new file mode 100644 index 00000000..05175ff0 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ImmunizationFhirToDhisTransformerUtils.java @@ -0,0 +1,72 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.TransformerException; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.AbstractImmunizationFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.instance.model.api.IDomainResource; +import org.hl7.fhir.r4.model.Immunization; +import org.hl7.fhir.r4.model.PrimitiveType; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Comparator; +import java.util.Set; + +@Component +@Scriptable +public class R4ImmunizationFhirToDhisTransformerUtils extends AbstractImmunizationFhirToDhisTransformerUtils +{ + public R4ImmunizationFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) + { + super( scriptExecutionContext ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Override + public int getMaxDoseSequence( @Nullable IDomainResource immunization ) throws TransformerException + { + if ( immunization == null ) + { + return 0; + } + return ((Immunization) immunization).getProtocolApplied().stream().map( Immunization.ImmunizationProtocolAppliedComponent::getDoseNumberPositiveIntType ) + .map( PrimitiveType::getValue ).max( Comparator.naturalOrder() ).orElse( 0 ); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4LocationFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4LocationFhirToDhisTransformerUtils.java new file mode 100644 index 00000000..fd108506 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4LocationFhirToDhisTransformerUtils.java @@ -0,0 +1,106 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.dhis.orgunit.OrganizationUnitService; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirServerResourceRepository; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.repository.FhirResourceRepository; +import org.dhis2.fhir.adapter.fhir.repository.HierarchicallyFhirResourceRepository; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.AbstractLocationFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.instance.model.api.IBaseBundle; +import org.hl7.fhir.instance.model.api.IBaseReference; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Location; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * FHIR version R4 implementation of {@link AbstractLocationFhirToDhisTransformerUtils}. + * + * @author volsch + */ +@Component +@Scriptable +public class R4LocationFhirToDhisTransformerUtils extends AbstractLocationFhirToDhisTransformerUtils +{ + public R4LocationFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, + @Nonnull OrganizationUnitService organizationUnitService, + @Nonnull FhirServerResourceRepository fhirServerResourceRepository, + @Nonnull FhirResourceRepository fhirResourceRepository, + @Nonnull HierarchicallyFhirResourceRepository hierarchicallyFhirResourceRepository ) + { + super( scriptExecutionContext, organizationUnitService, fhirServerResourceRepository, fhirResourceRepository, hierarchicallyFhirResourceRepository ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nullable + @Override + protected IBaseReference getParentReference( @Nullable IBaseResource resource ) + { + if ( resource == null ) + { + return null; + } + return ((Location) resource).getPartOf(); + } + + @Nonnull + @Override + protected List extractResources( @Nullable IBaseBundle bundle ) + { + if ( bundle == null ) + { + return Collections.emptyList(); + } + + final Bundle b = (Bundle) bundle; + if ( b.getEntry() == null ) + { + return Collections.emptyList(); + } + + return b.getEntry().stream().map( Bundle.BundleEntryComponent::getResource ).collect( Collectors.toList() ); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ObservationFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ObservationFhirToDhisTransformerUtils.java new file mode 100644 index 00000000..9a3b5eaa --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ObservationFhirToDhisTransformerUtils.java @@ -0,0 +1,116 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.AbstractObservationFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.instance.model.api.IBaseBackboneElement; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.ICompositeType; +import org.hl7.fhir.r4.model.Observation; +import org.hl7.fhir.r4.model.Observation.ObservationComponentComponent; +import org.hl7.fhir.r4.model.ResourceType; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Set; + +@Component +@Scriptable +public class R4ObservationFhirToDhisTransformerUtils extends AbstractObservationFhirToDhisTransformerUtils +{ + public R4ObservationFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, @Nonnull R4FhirClientFhirToDhisTransformerUtils clientTransformUtils, + @Nonnull R4CodeFhirToDhisTransformerUtils codeTransformerUtils ) + { + super( scriptExecutionContext, clientTransformUtils, codeTransformerUtils ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nonnull + @Override + public String getResourceName() + { + return ResourceType.Observation.name(); + } + + @Nullable + @Override + public ICompositeType getCodes( @Nullable IBaseResource resource ) + { + return (resource == null) ? null : ((Observation) resource).getCode(); + } + + @Nullable + @Override + public String getComponentText( @Nullable IBaseResource resource ) + { + final Observation observation = (Observation) resource; + if ( (observation == null) || !observation.hasComponent() ) + { + return null; + } + + final StringBuilder text = new StringBuilder(); + for ( final ObservationComponentComponent component : observation.getComponent() ) + { + if ( component.hasValueStringType() ) + { + if ( text.length() > 0 ) + { + text.append( COMPONENT_SEPARATOR ); + } + text.append( component.getValue().toString() ); + } + } + return (text.length() == 0) ? null : text.toString(); + } + + @Override + @Nullable + public IBaseBackboneElement getBackboneElement( @Nullable List backboneElements, @Nonnull String system, @Nonnull String code ) + { + if ( backboneElements == null ) + { + return null; + } + return backboneElements.stream().map( ObservationComponentComponent.class::cast ) + .filter( c -> getCodeTransformerUtils().containsCode( c.getCode(), system, code ) ) + .findFirst().orElse( new ObservationComponentComponent() ); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4OrganizationFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4OrganizationFhirToDhisTransformerUtils.java new file mode 100644 index 00000000..4ae3a90c --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4OrganizationFhirToDhisTransformerUtils.java @@ -0,0 +1,106 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.dhis.orgunit.OrganizationUnitService; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirServerResourceRepository; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.repository.FhirResourceRepository; +import org.dhis2.fhir.adapter.fhir.repository.HierarchicallyFhirResourceRepository; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.AbstractOrganizationFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.instance.model.api.IBaseBundle; +import org.hl7.fhir.instance.model.api.IBaseReference; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Organization; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * FHIR version R4 implementation of {@link AbstractOrganizationFhirToDhisTransformerUtils}. + * + * @author volsch + */ +@Component +@Scriptable +public class R4OrganizationFhirToDhisTransformerUtils extends AbstractOrganizationFhirToDhisTransformerUtils +{ + public R4OrganizationFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, + @Nonnull OrganizationUnitService organizationUnitService, + @Nonnull FhirServerResourceRepository fhirServerResourceRepository, + @Nonnull FhirResourceRepository fhirResourceRepository, + @Nonnull HierarchicallyFhirResourceRepository hierarchicallyFhirResourceRepository ) + { + super( scriptExecutionContext, organizationUnitService, fhirServerResourceRepository, fhirResourceRepository, hierarchicallyFhirResourceRepository ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nullable + @Override + protected IBaseReference getParentReference( @Nullable IBaseResource resource ) + { + if ( resource == null ) + { + return null; + } + return ((Organization) resource).getPartOf(); + } + + @Nonnull + @Override + protected List extractResources( @Nullable IBaseBundle bundle ) + { + if ( bundle == null ) + { + return Collections.emptyList(); + } + + final Bundle b = (Bundle) bundle; + if ( b.getEntry() == null ) + { + return Collections.emptyList(); + } + + return b.getEntry().stream().map( Bundle.BundleEntryComponent::getResource ).collect( Collectors.toList() ); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4PatientFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4PatientFhirToDhisTransformerUtils.java new file mode 100644 index 00000000..446739c1 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4PatientFhirToDhisTransformerUtils.java @@ -0,0 +1,102 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.TransformerMappingException; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.AbstractPatientFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.hl7.fhir.instance.model.api.ICompositeType; +import org.hl7.fhir.instance.model.api.IDomainResource; +import org.hl7.fhir.r4.model.Address; +import org.hl7.fhir.r4.model.Extension; +import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.Type; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Set; + +/** + * FHIR version R4 implementation of {@link AbstractPatientFhirToDhisTransformerUtils}. + * + * @author volsch + */ +@Component +@Scriptable +public class R4PatientFhirToDhisTransformerUtils extends AbstractPatientFhirToDhisTransformerUtils +{ + public R4PatientFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) + { + super( scriptExecutionContext ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nullable + @Override + public ICompositeType getBirthPlaceAddress( @Nullable IDomainResource patient ) + { + if ( patient == null ) + { + return null; + } + + final Patient p = (Patient) patient; + final List birthPlaceExtensions = p.getExtensionsByUrl( BIRTH_PLACE_URI ); + if ( birthPlaceExtensions.isEmpty() ) + { + return null; + } + if ( birthPlaceExtensions.size() > 1 ) + { + throw new TransformerMappingException( "Patient contains " + birthPlaceExtensions.size() + " birth places." ); + } + + final Type value = birthPlaceExtensions.get( 0 ).getValue(); + if ( (value == null) || value.isEmpty() ) + { + return null; + } + + if ( !(value instanceof Address) ) + { + throw new TransformerMappingException( "Patient contains birth place that is no address: " + value.fhirType() ); + } + return (Address) value; + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ProgramStageFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ProgramStageFhirToDhisTransformerUtils.java new file mode 100644 index 00000000..8a985632 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ProgramStageFhirToDhisTransformerUtils.java @@ -0,0 +1,86 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.AbstractProgramStageFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.dhis2.fhir.adapter.util.CastUtils; +import org.hl7.fhir.r4.model.BaseDateTimeType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.temporal.Temporal; +import java.util.Date; +import java.util.Set; + +/** + * FHIR version R4 implementation of {@link AbstractProgramStageFhirToDhisTransformerUtils}. + * + * @author volsch + */ +@Component +@Scriptable +public class R4ProgramStageFhirToDhisTransformerUtils extends AbstractProgramStageFhirToDhisTransformerUtils +{ + private final Logger logger = LoggerFactory.getLogger( getClass() ); + + private final ZoneId zoneId = ZoneId.systemDefault(); + + public R4ProgramStageFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) + { + super( scriptExecutionContext ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Override + @Nullable + protected LocalDate castDate( @Nonnull Object date ) + { + return CastUtils.cast( date, + BaseDateTimeType.class, d -> { + final Date result = d.getValue(); + return LocalDate.from( result.toInstant().atZone( zoneId ) ); + }, + Date.class, d -> LocalDate.from( d.toInstant().atZone( zoneId ) ), + Temporal.class, LocalDate::from ); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4VitalSignFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4VitalSignFhirToDhisTransformerUtils.java new file mode 100644 index 00000000..1a30cf04 --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4VitalSignFhirToDhisTransformerUtils.java @@ -0,0 +1,162 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.TransformerDataException; +import org.dhis2.fhir.adapter.fhir.transform.TransformerMappingException; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.AbstractVitalSignFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.model.HeightUnit; +import org.dhis2.fhir.adapter.model.WeightUnit; +import org.dhis2.fhir.adapter.scriptable.Scriptable; +import org.dhis2.fhir.adapter.util.NameUtils; +import org.hl7.fhir.instance.model.api.ICompositeType; +import org.hl7.fhir.r4.model.Quantity; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.math.BigDecimal; +import java.util.Set; + +@Component +@Scriptable +public class R4VitalSignFhirToDhisTransformerUtils extends AbstractVitalSignFhirToDhisTransformerUtils +{ + public static final String UNIT_SYSTEM = "http://unitsofmeasure.org"; + + public R4VitalSignFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) + { + super( scriptExecutionContext ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Nullable + @Override + public Double getWeight( @Nullable ICompositeType value, @Nullable Object weightUnit, boolean round ) throws TransformerDataException + { + if ( value == null ) + { + return null; + } + + if ( weightUnit == null ) + { + throw new TransformerMappingException( "Weight unit has not been specified." ); + } + final WeightUnit resultingWeightUnit; + try + { + resultingWeightUnit = NameUtils.toEnumValue( WeightUnit.class, weightUnit ); + } + catch ( IllegalArgumentException e ) + { + throw new TransformerMappingException( "Specified weight unit is invalid: " + weightUnit ); + } + + if ( !(value instanceof Quantity) ) + { + throw new TransformerDataException( "Weight must be included as quantity, but element is " + value.getClass().getSimpleName() + "." ); + } + final Quantity quantity = (Quantity) value; + + if ( !UNIT_SYSTEM.equals( quantity.getSystem() ) ) + { + throw new TransformerDataException( UNIT_SYSTEM + " is expected as unit system: " + quantity.getSystem() ); + } + final WeightUnit actualWeightUnit = WeightUnit.getByUcumCode( quantity.getCode() ); + if ( actualWeightUnit == null ) + { + throw new TransformerDataException( "Unknown UCUM weight unit code: " + quantity.getCode() ); + } + + final BigDecimal actualValue = quantity.getValue(); + if ( actualValue == null ) + { + return null; + } + final double convertedValue = actualWeightUnit.convertTo( actualValue.doubleValue(), resultingWeightUnit ); + return round ? Math.round( convertedValue ) : convertedValue; + } + + @Nullable + @Override + public Double getHeight( @Nullable ICompositeType value, @Nullable Object heightUnit, boolean round ) throws TransformerDataException + { + if ( value == null ) + { + return null; + } + + if ( heightUnit == null ) + { + throw new TransformerMappingException( "Height unit has not been specified." ); + } + final HeightUnit resultingHeightUnit; + try + { + resultingHeightUnit = NameUtils.toEnumValue( HeightUnit.class, heightUnit ); + } + catch ( IllegalArgumentException e ) + { + throw new TransformerMappingException( "Specified height unit is invalid: " + heightUnit ); + } + + if ( !(value instanceof Quantity) ) + { + throw new TransformerDataException( "Height must be included as quantity, but element is " + value.getClass().getSimpleName() + "." ); + } + final Quantity quantity = (Quantity) value; + + if ( !UNIT_SYSTEM.equals( quantity.getSystem() ) ) + { + throw new TransformerDataException( UNIT_SYSTEM + " is expected as unit system: " + quantity.getSystem() ); + } + final HeightUnit actualHeightUnit = HeightUnit.getByUcumCode( quantity.getCode() ); + if ( actualHeightUnit == null ) + { + throw new TransformerDataException( "Unknown UCUM height unit code: " + quantity.getCode() ); + } + + final BigDecimal actualValue = quantity.getValue(); + if ( actualValue == null ) + { + return null; + } + final double convertedValue = actualHeightUnit.convertTo( actualValue.doubleValue(), resultingHeightUnit ); + return round ? Math.round( convertedValue ) : convertedValue; + } +} diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4AdministrativeGenderToStringConverterTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4AdministrativeGenderToStringConverterTest.java new file mode 100644 index 00000000..72eed11b --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4AdministrativeGenderToStringConverterTest.java @@ -0,0 +1,102 @@ +package org.dhis2.fhir.adapter.fhir.converter.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 org.dhis2.fhir.adapter.fhir.metadata.model.Constant; +import org.dhis2.fhir.adapter.fhir.metadata.model.ConstantResolver; +import org.hl7.fhir.r4.model.Enumerations; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.Optional; + +/** + * Unit tests for {@link R4AdministrativeGenderToStringConverter}. + * + * @author volsch + */ +public class R4AdministrativeGenderToStringConverterTest +{ + @Mock + private ConstantResolver constantResolver; + + @InjectMocks + private R4AdministrativeGenderToStringConverter converter; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Test + public void testMale() + { + final Constant constant = new Constant(); + constant.setValue( "MaLe" ); + Mockito.doReturn( Optional.of( constant ) ).when( constantResolver ).findOneByCode( Mockito.eq( "GENDER_MALE" ) ); + Assert.assertEquals( "MaLe", converter.convert( Enumerations.AdministrativeGender.MALE ) ); + } + + @Test + public void testFemale() + { + final Constant constant = new Constant(); + constant.setValue( "FeMaLe" ); + Mockito.doReturn( Optional.of( constant ) ).when( constantResolver ).findOneByCode( Mockito.eq( "GENDER_FEMALE" ) ); + Assert.assertEquals( "FeMaLe", converter.convert( Enumerations.AdministrativeGender.FEMALE ) ); + } + + @Test + public void testNull() + { + Assert.assertNull( converter.convert( Enumerations.AdministrativeGender.NULL ) ); + } + + @Test + public void testUnknown() + { + Assert.assertNull( converter.convert( Enumerations.AdministrativeGender.UNKNOWN ) ); + } + + @Test + public void testOther() + { + Assert.assertNull( converter.convert( Enumerations.AdministrativeGender.OTHER ) ); + } + + @Test + public void testNullValue() + { + Assert.assertNull( converter.convert( null ) ); + } +} \ No newline at end of file diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4BaseDateTimeTypeToDateStringConverterTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4BaseDateTimeTypeToDateStringConverterTest.java new file mode 100644 index 00000000..b42358f0 --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4BaseDateTimeTypeToDateStringConverterTest.java @@ -0,0 +1,63 @@ +package org.dhis2.fhir.adapter.fhir.converter.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 org.hl7.fhir.r4.model.DateTimeType; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.sql.Date; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +/** + * Unit tests for {@link R4BaseDateTimeTypeToDateStringConverter}. + * + * @author volsch + */ +public class R4BaseDateTimeTypeToDateStringConverterTest +{ + @InjectMocks + private R4BaseDateTimeTypeToDateStringConverter converter; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Test + public void fullTimestamp() + { + final ZonedDateTime zonedDateTime = ZonedDateTime.of( 2018, 7, 27, 15, 2, 43, 123456000, ZoneId.of( "CET" ) ); + Assert.assertEquals( "2018-07-27", + converter.doConvert( new DateTimeType( Date.from( zonedDateTime.toInstant() ) ) ) ); + } +} \ No newline at end of file diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4BaseDateTimeTypeToZonedDateTimeConverterTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4BaseDateTimeTypeToZonedDateTimeConverterTest.java new file mode 100644 index 00000000..3621855d --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4BaseDateTimeTypeToZonedDateTimeConverterTest.java @@ -0,0 +1,64 @@ +package org.dhis2.fhir.adapter.fhir.converter.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 org.hl7.fhir.r4.model.DateTimeType; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.sql.Date; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +/** + * Unit tests for {@link R4BaseDateTimeTypeToZonedDateTimeConverter}. + * + * @author volsch + */ +public class R4BaseDateTimeTypeToZonedDateTimeConverterTest +{ + @InjectMocks + private R4BaseDateTimeTypeToZonedDateTimeConverter converter; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Test + public void fullTimestamp() + { + final ZonedDateTime zonedDateTime = ZonedDateTime.of( 2018, 7, 27, 15, 2, 43, 123000000, ZoneId.of( "CET" ) ); + final ZonedDateTime result = converter.doConvert( new DateTimeType( Date.from( zonedDateTime.toInstant() ) ) ); + Assert.assertNotNull( result ); + Assert.assertEquals( zonedDateTime.toLocalDateTime(), result.toLocalDateTime() ); + } +} \ No newline at end of file diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4QuantityToStringConverterTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4QuantityToStringConverterTest.java new file mode 100644 index 00000000..778bba12 --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/converter/r4/R4QuantityToStringConverterTest.java @@ -0,0 +1,58 @@ +package org.dhis2.fhir.adapter.fhir.converter.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 org.hl7.fhir.r4.model.Quantity; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** + * Unit tests for {@link R4QuantityToStringConverter}. + * + * @author volsch + */ +public class R4QuantityToStringConverterTest +{ + @InjectMocks + private R4QuantityToStringConverter converter; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Test + public void doubleQuantity() + { + final Quantity quantity = new Quantity( 27.3 ); + Assert.assertEquals( "27.3", converter.convert( quantity ) ); + } +} \ No newline at end of file diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/ReferenceFhirToDhisTransformerUtilsTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/ReferenceFhirToDhisTransformerUtilsTest.java new file mode 100644 index 00000000..2af3ac12 --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/ReferenceFhirToDhisTransformerUtilsTest.java @@ -0,0 +1,261 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util; + +/* + * 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.context.FhirContext; +import org.dhis2.fhir.adapter.fhir.metadata.model.FhirResourceType; +import org.dhis2.fhir.adapter.fhir.metadata.model.FhirServer; +import org.dhis2.fhir.adapter.fhir.metadata.model.FhirServerResource; +import org.dhis2.fhir.adapter.fhir.metadata.model.SubscriptionFhirEndpoint; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirServerResourceRepository; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.repository.FhirResourceRepository; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecution; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.FhirToDhisTransformerContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.model.FhirRequest; +import org.dhis2.fhir.adapter.fhir.transform.fhir.model.ResourceSystem; +import org.hl7.fhir.instance.model.api.IBaseReference; +import org.hl7.fhir.instance.model.api.IIdType; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.Resource; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +/** + * Unit tests for {@link ReferenceFhirToDhisTransformerUtils}. + * + * @author volsch + */ +public class ReferenceFhirToDhisTransformerUtilsTest +{ + @Mock + private ScriptExecutionContext scriptExecutionContext; + + @Mock + private FhirServerResourceRepository fhirServerResourceRepository; + + @Mock + private FhirResourceRepository fhirResourceRepository; + + @Mock + private FhirToDhisTransformerContext context; + + @Mock + private FhirRequest request; + + @Mock + private ScriptExecution scriptExecution; + + @Mock + private Map variables; + + @Mock + private IBaseReference reference; + + @InjectMocks + private ReferenceFhirToDhisTransformerUtils utils; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Test + public void getResourceNull() + { + Assert.assertNull( utils.getResource( null, "PATIENT", false ) ); + } + + @Test + public void getIncludedResource() + { + final Patient resource = new Patient(); + final IIdType id = new IdType( "Patient", "123" ); + Mockito.doReturn( resource ).when( reference ).getResource(); + Assert.assertSame( resource, utils.getResource( reference, "PATIENT", false ) ); + } + + @Test + public void getIncludedResourceNoType() + { + final Patient resource = new Patient(); + final IIdType id = new IdType( null, "123" ); + Mockito.doReturn( resource ).when( reference ).getResource(); + Assert.assertSame( resource, utils.getResource( reference, "PATIENT", false ) ); + } + + @Test + public void getIncludedResourceNoRequestType() + { + final Patient resource = new Patient(); + final IIdType id = new IdType( "Patient", "123" ); + Mockito.doReturn( resource ).when( reference ).getResource(); + Assert.assertSame( resource, utils.getResource( reference, null, false ) ); + } + + @Test + public void getResource() + { + final SubscriptionFhirEndpoint subscriptionFhirEndpoint = new SubscriptionFhirEndpoint(); + final UUID fhirServerId = UUID.randomUUID(); + final FhirServer fhirServer = new FhirServer(); + fhirServer.setId( fhirServerId ); + fhirServer.setFhirVersion( FhirVersion.R4 ); + fhirServer.setFhirEndpoint( subscriptionFhirEndpoint ); + final FhirContext fhirContext = FhirContext.forR4(); + final UUID fhirServerResourceId = UUID.randomUUID(); + final FhirServerResource fhirServerResource = new FhirServerResource(); + fhirServerResource.setId( fhirServerResourceId ); + fhirServerResource.setFhirServer( fhirServer ); + final ResourceSystem resourceSystem = new ResourceSystem( FhirResourceType.ORGANIZATION, "http://test.com", "OT_", null, null ); + Mockito.doReturn( scriptExecution ).when( scriptExecutionContext ).getScriptExecution(); + Mockito.doReturn( variables ).when( scriptExecution ).getVariables(); + Mockito.doReturn( context ).when( variables ).get( Mockito.eq( "context" ) ); + Mockito.doReturn( request ).when( context ).getFhirRequest(); + Mockito.doReturn( fhirServerResourceId ).when( request ).getFhirServerResourceId(); + Mockito.doReturn( FhirVersion.R4 ).when( request ).getVersion(); + Mockito.doReturn( Optional.of( resourceSystem ) ).when( request ).getOptionalResourceSystem( FhirResourceType.ORGANIZATION ); + Mockito.doReturn( Optional.of( fhirServerResource ) ).when( fhirServerResourceRepository ).findOneByIdCached( Mockito.eq( fhirServerResourceId ) ); + Mockito.doReturn( Optional.of( fhirContext ) ).when( fhirResourceRepository ).findFhirContext( Mockito.eq( FhirVersion.R4 ) ); + + final Patient resource = new Patient(); + final IIdType id = new IdType( "Patient", "123" ); + resource.setId( id ); + final Reference reference = new Reference( id ); + + Mockito.doReturn( Optional.of( resource ) ).when( fhirResourceRepository ) + .find( Mockito.eq( fhirServerId ), Mockito.eq( FhirVersion.R4 ), + Mockito.same( subscriptionFhirEndpoint ), Mockito.eq( "Patient" ), Mockito.eq( "123" ) ); + + final Resource result = (Resource) utils.getResource( reference, null, false ); + Assert.assertTrue( result instanceof Patient ); + Assert.assertEquals( id, result.getIdElement() ); + Assert.assertNotSame( resource, result ); + + Mockito.verify( fhirResourceRepository ).find( Mockito.eq( fhirServerId ), Mockito.eq( FhirVersion.R4 ), + Mockito.same( subscriptionFhirEndpoint ), Mockito.eq( "Patient" ), Mockito.eq( "123" ) ); + } + + @Test + public void getResourceRefreshed() + { + final SubscriptionFhirEndpoint subscriptionFhirEndpoint = new SubscriptionFhirEndpoint(); + final UUID fhirServerId = UUID.randomUUID(); + final FhirServer fhirServer = new FhirServer(); + fhirServer.setId( fhirServerId ); + fhirServer.setFhirVersion( FhirVersion.R4 ); + fhirServer.setFhirEndpoint( subscriptionFhirEndpoint ); + final FhirContext fhirContext = FhirContext.forR4(); + final UUID fhirServerResourceId = UUID.randomUUID(); + final FhirServerResource fhirServerResource = new FhirServerResource(); + fhirServerResource.setId( fhirServerResourceId ); + fhirServerResource.setFhirServer( fhirServer ); + final ResourceSystem resourceSystem = new ResourceSystem( FhirResourceType.ORGANIZATION, "http://test.com", "OT_", null, null ); + Mockito.doReturn( scriptExecution ).when( scriptExecutionContext ).getScriptExecution(); + Mockito.doReturn( variables ).when( scriptExecution ).getVariables(); + Mockito.doReturn( context ).when( variables ).get( Mockito.eq( "context" ) ); + Mockito.doReturn( request ).when( context ).getFhirRequest(); + Mockito.doReturn( fhirServerResourceId ).when( request ).getFhirServerResourceId(); + Mockito.doReturn( FhirVersion.R4 ).when( request ).getVersion(); + Mockito.doReturn( Optional.of( resourceSystem ) ).when( request ).getOptionalResourceSystem( FhirResourceType.ORGANIZATION ); + Mockito.doReturn( Optional.of( fhirServerResource ) ).when( fhirServerResourceRepository ).findOneByIdCached( Mockito.eq( fhirServerResourceId ) ); + Mockito.doReturn( Optional.of( fhirContext ) ).when( fhirResourceRepository ).findFhirContext( Mockito.eq( FhirVersion.R4 ) ); + + final Patient resource = new Patient(); + final IIdType id = new IdType( "Patient", "123" ); + resource.setId( id ); + final Reference reference = new Reference( id ); + + Mockito.doReturn( Optional.of( resource ) ).when( fhirResourceRepository ) + .findRefreshed( Mockito.eq( fhirServerId ), Mockito.eq( FhirVersion.R4 ), + Mockito.same( subscriptionFhirEndpoint ), Mockito.eq( "Patient" ), Mockito.eq( "123" ) ); + + final Resource result = (Resource) utils.getResource( reference, null, true ); + Assert.assertTrue( result instanceof Patient ); + Assert.assertEquals( id, result.getIdElement() ); + Assert.assertNotSame( resource, result ); + + Mockito.verify( fhirResourceRepository ).findRefreshed( Mockito.eq( fhirServerId ), Mockito.eq( FhirVersion.R4 ), + Mockito.same( subscriptionFhirEndpoint ), Mockito.eq( "Patient" ), Mockito.eq( "123" ) ); + } + + @Test + public void initReference() + { + final SubscriptionFhirEndpoint subscriptionFhirEndpoint = new SubscriptionFhirEndpoint(); + final UUID fhirServerId = UUID.randomUUID(); + final FhirServer fhirServer = new FhirServer(); + fhirServer.setId( fhirServerId ); + fhirServer.setFhirVersion( FhirVersion.R4 ); + fhirServer.setFhirEndpoint( subscriptionFhirEndpoint ); + final FhirContext fhirContext = FhirContext.forR4(); + final UUID fhirServerResourceId = UUID.randomUUID(); + final FhirServerResource fhirServerResource = new FhirServerResource(); + fhirServerResource.setId( fhirServerResourceId ); + fhirServerResource.setFhirServer( fhirServer ); + final ResourceSystem resourceSystem = new ResourceSystem( FhirResourceType.ORGANIZATION, "http://test.com", "OT_", null, null ); + Mockito.doReturn( scriptExecution ).when( scriptExecutionContext ).getScriptExecution(); + Mockito.doReturn( variables ).when( scriptExecution ).getVariables(); + Mockito.doReturn( context ).when( variables ).get( Mockito.eq( "context" ) ); + Mockito.doReturn( request ).when( context ).getFhirRequest(); + Mockito.doReturn( fhirServerResourceId ).when( request ).getFhirServerResourceId(); + Mockito.doReturn( FhirVersion.R4 ).when( request ).getVersion(); + Mockito.doReturn( Optional.of( resourceSystem ) ).when( request ).getOptionalResourceSystem( FhirResourceType.ORGANIZATION ); + Mockito.doReturn( Optional.of( fhirServerResource ) ).when( fhirServerResourceRepository ).findOneByIdCached( Mockito.eq( fhirServerResourceId ) ); + Mockito.doReturn( Optional.of( fhirContext ) ).when( fhirResourceRepository ).findFhirContext( Mockito.eq( FhirVersion.R4 ) ); + + final Patient resource = new Patient(); + final IIdType id = new IdType( "Patient", "123" ); + resource.setId( id ); + final Reference reference = new Reference( id ); + + Mockito.doReturn( Optional.of( resource ) ).when( fhirResourceRepository ) + .find( Mockito.eq( fhirServerId ), Mockito.eq( FhirVersion.R4 ), + Mockito.same( subscriptionFhirEndpoint ), Mockito.eq( "Patient" ), Mockito.eq( "123" ) ); + + utils.initReference( reference, "PATIENT" ); + Assert.assertTrue( reference.getResource() instanceof Patient ); + Assert.assertEquals( id, reference.getResource().getIdElement() ); + Assert.assertNotSame( resource, reference.getResource() ); + + Mockito.verify( fhirResourceRepository ).find( Mockito.eq( fhirServerId ), Mockito.eq( FhirVersion.R4 ), + Mockito.same( subscriptionFhirEndpoint ), Mockito.eq( "Patient" ), Mockito.eq( "123" ) ); + } +} \ No newline at end of file diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4AddressFhirToDhisTransformerUtilsTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4AddressFhirToDhisTransformerUtilsTest.java new file mode 100644 index 00000000..6b3cfda6 --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4AddressFhirToDhisTransformerUtilsTest.java @@ -0,0 +1,180 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.hl7.fhir.r4.model.Address; +import org.hl7.fhir.r4.model.Period; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Unit tests for {@link R4AddressFhirToDhisTransformerUtils}. + * + * @author volsch + */ +public class R4AddressFhirToDhisTransformerUtilsTest +{ + @Mock + private ScriptExecutionContext scriptExecutionContext; + + @InjectMocks + private R4DateTimeFhirToDhisTransformerUtils dateTimeFhirToDhisTransformerUtils; + + private R4AddressFhirToDhisTransformerUtils utils; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Before + public void before() + { + utils = new R4AddressFhirToDhisTransformerUtils( scriptExecutionContext, dateTimeFhirToDhisTransformerUtils ); + } + + @Test + public void primaryExpired() + { + final List
addresses = new ArrayList<>(); + addresses.add( new Address().setType( Address.AddressType.PHYSICAL ).setUse( Address.AddressUse.HOME ) + .setPeriod( new Period().setEnd( Date.from( ZonedDateTime.now().minusDays( 1 ).toInstant() ) ) ) ); + addresses.add( new Address().setType( Address.AddressType.POSTAL ).setUse( Address.AddressUse.OLD ) ); + Assert.assertSame( addresses.get( 1 ), utils.getPrimaryAddress( addresses ) ); + } + + @Test + public void primaryTemp() + { + final List
addresses = new ArrayList<>(); + addresses.add( new Address().setType( Address.AddressType.PHYSICAL ).setUse( Address.AddressUse.TEMP ) ); + addresses.add( new Address().setType( Address.AddressType.PHYSICAL ).setUse( Address.AddressUse.OLD ) ); + Assert.assertSame( addresses.get( 0 ), utils.getPrimaryAddress( addresses ) ); + } + + @Test + public void primaryWork() + { + final List
addresses = new ArrayList<>(); + addresses.add( new Address().setType( Address.AddressType.PHYSICAL ).setUse( Address.AddressUse.HOME ) ); + addresses.add( new Address().setType( Address.AddressType.PHYSICAL ).setUse( Address.AddressUse.WORK ) ); + Assert.assertSame( addresses.get( 0 ), utils.getPrimaryAddress( addresses ) ); + } + + @Test + public void primaryNull() + { + final List
addresses = new ArrayList<>(); + addresses.add( new Address().setType( Address.AddressType.PHYSICAL ).setUse( Address.AddressUse.NULL ) ); + addresses.add( new Address().setType( Address.AddressType.PHYSICAL ).setUse( Address.AddressUse.WORK ) ); + Assert.assertSame( addresses.get( 0 ), utils.getPrimaryAddress( addresses ) ); + } + + @Test + public void primaryUnspecified() + { + final List
addresses = new ArrayList<>(); + addresses.add( new Address().setType( Address.AddressType.PHYSICAL ) ); + addresses.add( new Address().setType( Address.AddressType.PHYSICAL ).setUse( Address.AddressUse.WORK ) ); + Assert.assertSame( addresses.get( 0 ), utils.getPrimaryAddress( addresses ) ); + } + + @Test + public void primaryPhysical() + { + final List
addresses = new ArrayList<>(); + addresses.add( new Address().setType( Address.AddressType.PHYSICAL ).setUse( Address.AddressUse.HOME ) ); + addresses.add( new Address().setType( Address.AddressType.POSTAL ).setUse( Address.AddressUse.HOME ) ); + Assert.assertSame( addresses.get( 0 ), utils.getPrimaryAddress( addresses ) ); + } + + @Test + public void primaryBoth() + { + final List
addresses = new ArrayList<>(); + addresses.add( new Address().setType( Address.AddressType.POSTAL ).setUse( Address.AddressUse.HOME ) ); + addresses.add( new Address().setType( Address.AddressType.BOTH ).setUse( Address.AddressUse.HOME ) ); + Assert.assertSame( addresses.get( 1 ), utils.getPrimaryAddress( addresses ) ); + } + + @Test + public void primaryEmpty() + { + final List
addresses = new ArrayList<>(); + Assert.assertNotNull( utils.getPrimaryAddress( addresses ) ); + } + + @Test + public void getSingleLine() + { + final Address address = new Address().addLine( "Lower Road 20" ).addLine( "Apartment 19" ); + Assert.assertEquals( "Lower Road 20 Apartment 19", utils.getSingleLine( address ) ); + } + + @Test + public void getSingleLineOneLine() + { + final Address address = new Address().addLine( "Lower Road 20" ); + Assert.assertEquals( "Lower Road 20", utils.getSingleLine( address ) ); + } + + @Test + public void getConstructedText() + { + final Address address = new Address().addLine( "Lower Road 20" ).addLine( "Apartment 19" ) + .setCity( "Freetown" ).setPostalCode( "2009" ).setState( "Other State" ).setCountry( "Sierra Leone" ); + Assert.assertEquals( "Lower Road 20 / Apartment 19 / 2009 Freetown / Other State", utils.getConstructedText( address ) ); + } + + @Test + public void getConstructedTextWithoutPostcode() + { + final Address address = new Address().addLine( "Lower Road 20" ).addLine( "Apartment 19" ) + .setCity( "Freetown" ).setState( "Other State" ).setCountry( "Sierra Leone" ); + Assert.assertEquals( "Lower Road 20 / Apartment 19 / Freetown / Other State", utils.getConstructedText( address ) ); + } + + @Test + public void getText() + { + final Address address = new Address().addLine( "Lower Road 20" ).addLine( "Apartment 19" ) + .setCity( "Freetown" ).setState( "Other State" ).setCountry( "Sierra Leone" ).setText( "Summary Address" ); + Assert.assertEquals( "Summary Address", utils.getText( address ) ); + } +} \ No newline at end of file diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4CodeFhirToDhisTransformerUtilsTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4CodeFhirToDhisTransformerUtilsTest.java new file mode 100644 index 00000000..21ec7c12 --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4CodeFhirToDhisTransformerUtilsTest.java @@ -0,0 +1,385 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.fhir.metadata.model.Code; +import org.dhis2.fhir.adapter.fhir.metadata.model.FhirResourceType; +import org.dhis2.fhir.adapter.fhir.metadata.model.System; +import org.dhis2.fhir.adapter.fhir.metadata.model.SystemCode; +import org.dhis2.fhir.adapter.fhir.metadata.repository.CodeRepository; +import org.dhis2.fhir.adapter.fhir.metadata.repository.SystemCodeRepository; +import org.dhis2.fhir.adapter.fhir.model.SystemCodeValue; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecution; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.FhirToDhisTransformerContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.model.FhirRequest; +import org.dhis2.fhir.adapter.fhir.transform.fhir.model.ResourceSystem; +import org.hl7.fhir.r4.model.CodeableConcept; +import org.hl7.fhir.r4.model.Coding; +import org.hl7.fhir.r4.model.Observation; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * Unit tests for {@link R4CodeFhirToDhisTransformerUtils}. + * + * @author volsch + */ +public class R4CodeFhirToDhisTransformerUtilsTest +{ + @Mock + private ScriptExecutionContext scriptExecutionContext; + + @Mock + private CodeRepository codeRepository; + + @Mock + private SystemCodeRepository systemCodeRepository; + + @Mock + private FhirToDhisTransformerContext context; + + @Mock + private FhirRequest request; + + @Mock + private ScriptExecution scriptExecution; + + @Mock + private Map variables; + + @InjectMocks + private R4CodeFhirToDhisTransformerUtils utils; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Test + public void getSystemCodeValuesNull() + { + Assert.assertTrue( utils.getSystemCodeValues( null ).isEmpty() ); + } + + @Test + public void getCodeSystemNull() + { + Assert.assertNull( utils.getCode( null, "http://test.com/1" ) ); + } + + @Test + public void getCodeNotFound() + { + final CodeableConcept codeableConcept = new CodeableConcept(); + codeableConcept.addCoding( new Coding().setSystem( "http://test.com/1" ).setCode( "C1" ) ) + .addCoding( new Coding().setSystem( "http://test.com/2" ).setCode( "C2" ) ); + Assert.assertNull( utils.getCode( codeableConcept, "http://test.com/3" ) ); + } + + @Test + public void getCode() + { + final CodeableConcept codeableConcept = new CodeableConcept(); + codeableConcept.addCoding( new Coding().setSystem( "http://test.com/1" ).setCode( "C1" ) ) + .addCoding( new Coding().setSystem( "http://test.com/2" ).setCode( "C2" ) ); + Assert.assertEquals( "C2", utils.getCode( codeableConcept, "http://test.com/2" ) ); + } + + @Test + public void getSystemCodeValues() + { + final CodeableConcept codeableConcept = new CodeableConcept(); + codeableConcept.addCoding( new Coding().setSystem( "http://test.com/1" ).setCode( "C1" ) ) + .addCoding( new Coding().setSystem( "http://test.com/2" ).setCode( "C2" ) ); + final List systemCodeValues = utils.getSystemCodeValues( codeableConcept ); + Assert.assertEquals( new SystemCodeValue( "http://test.com/1", "C1" ), systemCodeValues.get( 0 ) ); + Assert.assertEquals( new SystemCodeValue( "http://test.com/2", "C2" ), systemCodeValues.get( 1 ) ); + } + + @Test + public void containsMappingCodeNull() + { + Assert.assertFalse( utils.containsMappingCode( null, new Object[0] ) ); + } + + @Test + public void containsMappingCodeEmptyArray() + { + Assert.assertFalse( utils.containsMappingCode( new CodeableConcept().addCoding(), new Object[0] ) ); + } + + @Test + public void containsMappingCodeFound() + { + final System system1 = new System(); + system1.setSystemUri( "http://test.com/3" ); + final SystemCode systemCode1 = new SystemCode(); + systemCode1.setSystemCode( "C3" ); + systemCode1.setSystem( system1 ); + systemCode1.setCode( new Code() ); + + final System system2 = new System(); + system2.setSystemUri( "http://test.com/2" ); + final SystemCode systemCode2 = new SystemCode(); + systemCode2.setSystemCode( "C2" ); + systemCode2.setSystem( system2 ); + systemCode2.setCode( new Code() ); + + Mockito.doReturn( Arrays.asList( systemCode1, systemCode2 ) ).when( systemCodeRepository ) + .findAllByCodes( Mockito.eq( Arrays.asList( "X_20", "X_21" ) ) ); + Assert.assertTrue( utils.containsMappingCode( new CodeableConcept().addCoding( new Coding().setSystem( "http://test.com/1" ).setCode( "C1" ) ) + .addCoding( new Coding().setSystem( "http://test.com/2" ).setCode( "C2" ) ), new Object[]{ "X_20", "X_21" } ) ); + } + + @Test + public void containsMappingCodeNotFound() + { + final System system1 = new System(); + system1.setSystemUri( "http://test.com/3" ); + final SystemCode systemCode1 = new SystemCode(); + systemCode1.setSystemCode( "C3" ); + systemCode1.setSystem( system1 ); + systemCode1.setCode( new Code() ); + + final System system2 = new System(); + system2.setSystemUri( "http://test.com/4" ); + final SystemCode systemCode2 = new SystemCode(); + systemCode2.setSystemCode( "C4" ); + systemCode2.setSystem( system2 ); + systemCode2.setCode( new Code() ); + + Mockito.doReturn( Arrays.asList( systemCode1, systemCode2 ) ).when( systemCodeRepository ) + .findAllByCodes( Mockito.eq( Arrays.asList( "X_20", "X_21" ) ) ); + Assert.assertFalse( utils.containsMappingCode( new CodeableConcept().addCoding( new Coding().setSystem( "http://test.com/1" ).setCode( "C1" ) ) + .addCoding( new Coding().setSystem( "http://test.com/2" ).setCode( "C2" ) ), new Object[]{ "X_20", "X_21" } ) ); + } + + @Test + public void containsCodeNull() + { + Assert.assertFalse( utils.containsCode( null, "http://test.com/2", "C2" ) ); + } + + @Test + public void containsCode() + { + final CodeableConcept codeableConcept = new CodeableConcept(); + codeableConcept.addCoding( new Coding().setSystem( "http://test.com/1" ).setCode( "C1" ) ) + .addCoding( new Coding().setSystem( "http://test.com/2" ).setCode( "C2" ) ); + Assert.assertTrue( utils.containsCode( codeableConcept, "http://test.com/2", "C2" ) ); + } + + @Test + public void containsCodeNot() + { + final CodeableConcept codeableConcept = new CodeableConcept(); + codeableConcept.addCoding( new Coding().setSystem( "http://test.com/1" ).setCode( "C1" ) ) + .addCoding( new Coding().setSystem( "http://test.com/2" ).setCode( "C2" ) ); + Assert.assertFalse( utils.containsCode( codeableConcept, "http://test.com/3", "C3" ) ); + } + + @Test + public void containsAnyCode() + { + final CodeableConcept codeableConcept = new CodeableConcept(); + codeableConcept.addCoding( new Coding().setSystem( "http://test.com/1" ).setCode( "C1" ) ) + .addCoding( new Coding().setSystem( "http://test.com/2" ).setCode( "C2" ) ); + final List systemCodeValues = Arrays.asList( + new SystemCodeValue( "http://test.com/3", "C3" ), + new SystemCodeValue( "http://test.com/2", "C2" ) + ); + Assert.assertTrue( utils.containsAnyCode( codeableConcept, systemCodeValues ) ); + } + + @Test + public void containsAnyCodeNot() + { + final CodeableConcept codeableConcept = new CodeableConcept(); + codeableConcept.addCoding( new Coding().setSystem( "http://test.com/1" ).setCode( "C1" ) ) + .addCoding( new Coding().setSystem( "http://test.com/2" ).setCode( "C2" ) ); + final List systemCodeValues = Arrays.asList( + new SystemCodeValue( "http://test.com/3", "C3" ), + new SystemCodeValue( "http://test.com/4", "C4" ) + ); + Assert.assertFalse( utils.containsAnyCode( codeableConcept, systemCodeValues ) ); + } + + @Test + public void containsAnyCodeConceptNull() + { + final List systemCodeValues = Arrays.asList( + new SystemCodeValue( "http://test.com/3", "C3" ), + new SystemCodeValue( "http://test.com/4", "C4" ) + ); + Assert.assertFalse( utils.containsAnyCode( null, systemCodeValues ) ); + } + + @Test + public void containsAnyCodeValuesNull() + { + final CodeableConcept codeableConcept = new CodeableConcept(); + codeableConcept.addCoding( new Coding().setSystem( "http://test.com/1" ).setCode( "C1" ) ) + .addCoding( new Coding().setSystem( "http://test.com/2" ).setCode( "C2" ) ); + Assert.assertFalse( utils.containsAnyCode( codeableConcept, null ) ); + } + + @Test + public void getSystemCodeValuesByMappingCodesNull() + { + Assert.assertTrue( utils.getSystemCodeValuesByMappingCodes( null ).isEmpty() ); + } + + @Test + public void getSystemCodeValuesByMappingCodesEmpty() + { + Assert.assertTrue( utils.getSystemCodeValuesByMappingCodes( new Object[0] ).isEmpty() ); + } + + @Test + public void getSystemCodeValuesByMappingCodes() + { + final System system1 = new System(); + system1.setSystemUri( "http://test.com/3" ); + final Code code1 = new Code(); + code1.setCode( "X_20" ); + final SystemCode systemCode1 = new SystemCode(); + systemCode1.setSystemCode( "C3" ); + systemCode1.setSystem( system1 ); + systemCode1.setCode( code1 ); + + final System system2 = new System(); + system2.setSystemUri( "http://test.com/4" ); + final Code code2 = new Code(); + code2.setCode( "X_21" ); + final SystemCode systemCode2 = new SystemCode(); + systemCode2.setSystemCode( "C4" ); + systemCode2.setSystem( system2 ); + systemCode2.setCode( code2 ); + + final System system3 = new System(); + system2.setSystemUri( "http://test.com/5" ); + final Code code3 = new Code(); + code3.setCode( "X_21" ); + final SystemCode systemCode3 = new SystemCode(); + systemCode3.setSystemCode( "C5" ); + systemCode3.setSystem( system2 ); + systemCode3.setCode( code3 ); + + Mockito.doReturn( Arrays.asList( systemCode1, systemCode2, systemCode3 ) ).when( systemCodeRepository ) + .findAllByCodes( Mockito.eq( Arrays.asList( "X_20", "X_21" ) ) ); + final Map> result = + utils.getSystemCodeValuesByMappingCodes( new Object[]{ "X_20", "X_21" } ); + + Assert.assertEquals( 2, result.size() ); + Assert.assertNotNull( result.get( "X_20" ) ); + Assert.assertEquals( 1, result.get( "X_20" ).size() ); + Assert.assertEquals( systemCode1.getCalculatedSystemCodeValue(), result.get( "X_20" ).get( 0 ) ); + Assert.assertNotNull( result.get( "X_21" ) ); + Assert.assertEquals( 2, result.get( "X_21" ).size() ); + Assert.assertEquals( systemCode2.getCalculatedSystemCodeValue(), result.get( "X_21" ).get( 0 ) ); + Assert.assertEquals( systemCode3.getCalculatedSystemCodeValue(), result.get( "X_21" ).get( 1 ) ); + } + + @Test + public void getResourceCodes() + { + final CodeableConcept codeableConcept = new CodeableConcept(); + codeableConcept.addCoding( new Coding().setSystem( "http://test.com/1" ).setCode( "C1" ) ) + .addCoding( new Coding().setSystem( "http://test.com/2" ).setCode( "C2" ) ); + final Observation observation = new Observation(); + observation.setCode( codeableConcept ); + final List systemCodeValues = utils.getResourceCodes( observation ); + Assert.assertNotNull( systemCodeValues ); + Assert.assertEquals( 2, systemCodeValues.size() ); + Assert.assertEquals( new SystemCodeValue( "http://test.com/1", "C1" ), systemCodeValues.get( 0 ) ); + Assert.assertEquals( new SystemCodeValue( "http://test.com/2", "C2" ), systemCodeValues.get( 1 ) ); + } + + @Test + public void getMappedCodeNotFound() + { + final ResourceSystem resourceSystem = new ResourceSystem( FhirResourceType.ORGANIZATION, "http://test.com/2", null, null, null ); + + Mockito.doReturn( scriptExecution ).when( scriptExecutionContext ).getScriptExecution(); + Mockito.doReturn( variables ).when( scriptExecution ).getVariables(); + Mockito.doReturn( context ).when( variables ).get( Mockito.eq( "context" ) ); + Mockito.doReturn( request ).when( context ).getFhirRequest(); + Mockito.doReturn( Optional.of( resourceSystem ) ).when( request ).getOptionalResourceSystem( FhirResourceType.ORGANIZATION ); + + Assert.assertNull( utils.getMappedCode( "TEST_1", "ORGANIZATION" ) ); + } + + @Test + public void getMappedCodeFound() + { + final ResourceSystem resourceSystem = new ResourceSystem( FhirResourceType.ORGANIZATION, "http://test.com/2", null, null, null ); + + Mockito.doReturn( scriptExecution ).when( scriptExecutionContext ).getScriptExecution(); + Mockito.doReturn( variables ).when( scriptExecution ).getVariables(); + Mockito.doReturn( context ).when( variables ).get( Mockito.eq( "context" ) ); + Mockito.doReturn( request ).when( context ).getFhirRequest(); + Mockito.doReturn( Optional.of( resourceSystem ) ).when( request ).getOptionalResourceSystem( FhirResourceType.ORGANIZATION ); + + final Code code = new Code(); + code.setCode( "ABC_1" ); + Mockito.doReturn( Collections.singletonList( code ) ).when( codeRepository ).findAllBySystemCodes( Mockito.eq( Collections.singleton( "http://test.com/2|TEST_1" ) ) ); + + Assert.assertEquals( "ABC_1", utils.getMappedCode( "TEST_1", "ORGANIZATION" ) ); + } + + @Test + public void getMappedCodeFoundMapped() + { + final ResourceSystem resourceSystem = new ResourceSystem( FhirResourceType.ORGANIZATION, "http://test.com/2", null, null, null ); + + Mockito.doReturn( scriptExecution ).when( scriptExecutionContext ).getScriptExecution(); + Mockito.doReturn( variables ).when( scriptExecution ).getVariables(); + Mockito.doReturn( context ).when( variables ).get( Mockito.eq( "context" ) ); + Mockito.doReturn( request ).when( context ).getFhirRequest(); + Mockito.doReturn( Optional.of( resourceSystem ) ).when( request ).getOptionalResourceSystem( FhirResourceType.ORGANIZATION ); + + final Code code = new Code(); + code.setCode( "ABC_1" ); + code.setMappedCode( "CBA_1" ); + Mockito.doReturn( Collections.singletonList( code ) ).when( codeRepository ).findAllBySystemCodes( Mockito.eq( Collections.singleton( "http://test.com/2|TEST_1" ) ) ); + + Assert.assertEquals( "CBA_1", utils.getMappedCode( "TEST_1", "ORGANIZATION" ) ); + } +} \ No newline at end of file diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ContactPointFhirToDhisTransformerUtilsTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ContactPointFhirToDhisTransformerUtilsTest.java new file mode 100644 index 00000000..d6af8609 --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ContactPointFhirToDhisTransformerUtilsTest.java @@ -0,0 +1,153 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.hl7.fhir.r4.model.ContactPoint; +import org.hl7.fhir.r4.model.Period; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Unit tests for {@link R4ContactPointFhirToDhisTransformerUtils}. + * + * @author volsch + */ +public class R4ContactPointFhirToDhisTransformerUtilsTest +{ + @Mock + private ScriptExecutionContext scriptExecutionContext; + + @InjectMocks + private R4DateTimeFhirToDhisTransformerUtils dateTimeFhirToDhisTransformerUtils; + + private R4ContactPointFhirToDhisTransformerUtils utils; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Before + public void before() + { + utils = new R4ContactPointFhirToDhisTransformerUtils( scriptExecutionContext, dateTimeFhirToDhisTransformerUtils ); + } + + @Test + public void primaryExpired() + { + final List contactPoints = new ArrayList<>(); + contactPoints.add( new ContactPoint().setRank( 1 ).setUse( ContactPoint.ContactPointUse.HOME ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4711" ) + .setPeriod( new Period().setEnd( Date.from( ZonedDateTime.now().minusDays( 1 ).toInstant() ) ) ) ); + contactPoints.add( new ContactPoint().setRank( 999 ).setUse( ContactPoint.ContactPointUse.OLD ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4712" ) ); + Assert.assertEquals( contactPoints.get( 1 ).getValue(), utils.getPhoneContactPointValue( contactPoints ) ); + } + + @Test + public void primaryEmail() + { + final List contactPoints = new ArrayList<>(); + contactPoints.add( new ContactPoint().setRank( 999 ).setUse( ContactPoint.ContactPointUse.OLD ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4712" ) ); + contactPoints.add( new ContactPoint().setRank( 1 ).setUse( ContactPoint.ContactPointUse.HOME ).setSystem( ContactPoint.ContactPointSystem.EMAIL ).setValue( "4711" ) ); + Assert.assertEquals( contactPoints.get( 0 ).getValue(), utils.getPhoneContactPointValue( contactPoints ) ); + } + + @Test + public void primaryRank() + { + final List contactPoints = new ArrayList<>(); + contactPoints.add( new ContactPoint().setRank( 1 ).setUse( ContactPoint.ContactPointUse.HOME ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4712" ) ); + contactPoints.add( new ContactPoint().setRank( 2 ).setUse( ContactPoint.ContactPointUse.HOME ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4711" ) ); + Assert.assertEquals( contactPoints.get( 0 ).getValue(), utils.getPhoneContactPointValue( contactPoints ) ); + } + + @Test + public void primaryTemp() + { + final List contactPoints = new ArrayList<>(); + contactPoints.add( new ContactPoint().setRank( 1 ).setUse( ContactPoint.ContactPointUse.OLD ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4711" ) ); + contactPoints.add( new ContactPoint().setRank( 1 ).setUse( ContactPoint.ContactPointUse.TEMP ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4712" ) ); + Assert.assertEquals( contactPoints.get( 1 ).getValue(), utils.getPhoneContactPointValue( contactPoints ) ); + } + + @Test + public void primaryWork() + { + final List contactPoints = new ArrayList<>(); + contactPoints.add( new ContactPoint().setRank( 1 ).setUse( ContactPoint.ContactPointUse.TEMP ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4711" ) ); + contactPoints.add( new ContactPoint().setRank( 1 ).setUse( ContactPoint.ContactPointUse.WORK ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4712" ) ); + Assert.assertEquals( contactPoints.get( 1 ).getValue(), utils.getPhoneContactPointValue( contactPoints ) ); + } + + @Test + public void primaryMobile() + { + final List contactPoints = new ArrayList<>(); + contactPoints.add( new ContactPoint().setRank( 1 ).setUse( ContactPoint.ContactPointUse.TEMP ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4711" ) ); + contactPoints.add( new ContactPoint().setRank( 1 ).setUse( ContactPoint.ContactPointUse.MOBILE ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4712" ) ); + Assert.assertEquals( contactPoints.get( 1 ).getValue(), utils.getPhoneContactPointValue( contactPoints ) ); + } + + @Test + public void primaryHome() + { + final List contactPoints = new ArrayList<>(); + contactPoints.add( new ContactPoint().setRank( 1 ).setUse( ContactPoint.ContactPointUse.TEMP ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4711" ) ); + contactPoints.add( new ContactPoint().setRank( 1 ).setUse( ContactPoint.ContactPointUse.HOME ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4712" ) ); + Assert.assertEquals( contactPoints.get( 1 ).getValue(), utils.getPhoneContactPointValue( contactPoints ) ); + } + + @Test + public void primaryNull() + { + final List contactPoints = new ArrayList<>(); + contactPoints.add( new ContactPoint().setRank( 1 ).setUse( ContactPoint.ContactPointUse.NULL ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4711" ) ); + contactPoints.add( new ContactPoint().setRank( 1 ).setUse( ContactPoint.ContactPointUse.TEMP ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4712" ) ); + Assert.assertEquals( contactPoints.get( 0 ).getValue(), utils.getPhoneContactPointValue( contactPoints ) ); + } + + @Test + public void primaryOther() + { + final List contactPoints = new ArrayList<>(); + contactPoints.add( new ContactPoint().setRank( 1 ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4711" ) ); + contactPoints.add( new ContactPoint().setRank( 1 ).setUse( ContactPoint.ContactPointUse.TEMP ).setSystem( ContactPoint.ContactPointSystem.PHONE ).setValue( "4712" ) ); + Assert.assertEquals( contactPoints.get( 0 ).getValue(), utils.getPhoneContactPointValue( contactPoints ) ); + } +} \ No newline at end of file diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4DateTimeFhirToDhisTransformerUtilsTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4DateTimeFhirToDhisTransformerUtilsTest.java new file mode 100644 index 00000000..05897031 --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4DateTimeFhirToDhisTransformerUtilsTest.java @@ -0,0 +1,256 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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.model.api.TemporalPrecisionEnum; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.model.DateUnit; +import org.hl7.fhir.r4.model.DateTimeType; +import org.hl7.fhir.r4.model.Period; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.time.LocalDate; +import java.time.ZonedDateTime; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +/** + * Unit tests for {@link R4DateTimeFhirToDhisTransformerUtils}. + * + * @author volsch + */ +public class R4DateTimeFhirToDhisTransformerUtilsTest +{ + @Mock + private ScriptExecutionContext scriptExecutionContext; + + @InjectMocks + private R4DateTimeFhirToDhisTransformerUtils utils; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Test + public void hasDayPrecisionDay() + { + Assert.assertTrue( utils.hasDayPrecision( new DateTimeType( new Date(), TemporalPrecisionEnum.DAY ) ) ); + } + + @Test + public void hasDayPrecisionSecond() + { + Assert.assertTrue( utils.hasDayPrecision( new DateTimeType( new Date(), TemporalPrecisionEnum.SECOND ) ) ); + } + + @Test + public void hasDayPrecisionNull() + { + Assert.assertTrue( utils.hasDayPrecision( null ) ); + } + + @Test + public void hasDayPrecisionMonth() + { + Assert.assertFalse( utils.hasDayPrecision( new DateTimeType( new Date(), TemporalPrecisionEnum.MONTH ) ) ); + } + + @Test + public void isValidNowNull() + { + Assert.assertTrue( utils.isValidNow( null ) ); + } + + @Test + public void isValidNowStart() + { + Assert.assertTrue( utils.isValidNow( new Period().setStart( Date.from( ZonedDateTime.now().plusDays( 2 ).toInstant() ) ) ) ); + } + + @Test + public void isValidNowEndFuture() + { + Assert.assertTrue( utils.isValidNow( new Period().setEnd( Date.from( ZonedDateTime.now().plusDays( 2 ).toInstant() ) ) ) ); + } + + @Test + public void isValidNowEndPast() + { + Assert.assertFalse( utils.isValidNow( new Period().setEnd( Date.from( ZonedDateTime.now().minusDays( 2 ).toInstant() ) ) ) ); + } + + @Test + public void getPreciseDateNull() + { + Assert.assertNull( utils.getPreciseDate( null ) ); + } + + @Test + public void getPreciseDateInternNull() + { + Assert.assertNull( utils.getPreciseDate( new DateTimeType( (Date) null ) ) ); + } + + @Test + public void getPreciseDateMonth() + { + Assert.assertNull( utils.getPreciseDate( new DateTimeType( new Date(), TemporalPrecisionEnum.MONTH ) ) ); + } + + @Test + public void getPreciseDateMinute() + { + Assert.assertNotNull( utils.getPreciseDate( new DateTimeType( new Date(), TemporalPrecisionEnum.SECOND ) ) ); + } + + + @Test + public void getPrecisePastDateNull() + { + Assert.assertNull( utils.getPrecisePastDate( null ) ); + } + + @Test + public void getPrecisePastDateInternNull() + { + Assert.assertNull( utils.getPrecisePastDate( new DateTimeType( (Date) null ) ) ); + } + + @Test + public void getPrecisePastDateMonth() + { + Assert.assertNull( utils.getPrecisePastDate( new DateTimeType( new Date( System.currentTimeMillis() - 1000 ), TemporalPrecisionEnum.MONTH ) ) ); + } + + @Test + public void getPrecisePastDateMinute() + { + Assert.assertNotNull( utils.getPrecisePastDate( new DateTimeType( new Date( System.currentTimeMillis() - 1000 ), TemporalPrecisionEnum.SECOND ) ) ); + } + + @Test + public void getPrecisePastDateFuture() + { + Assert.assertNull( utils.getPrecisePastDate( new DateTimeType( new Date( System.currentTimeMillis() + 20_000 ), TemporalPrecisionEnum.SECOND ) ) ); + } + + @Test + public void getAgeRelative() + { + final GregorianCalendar cal1 = new GregorianCalendar( 2017, Calendar.JUNE, 8, 15, 16, 17 ); + final GregorianCalendar cal2 = new GregorianCalendar( 2017, Calendar.JUNE, 6, 14, 16, 17 ); + Assert.assertEquals( (Integer) 2, utils.getAge( new DateTimeType( cal1.getTime() ), cal2.getTime(), DateUnit.DAYS ) ); + } + + @Test + public void getAgeToday() + { + Assert.assertEquals( (Integer) 2, utils.getAge( LocalDate.now().minusDays( 2 ), DateUnit.DAYS ) ); + } + + @Test + public void getAgeNull() + { + Assert.assertNull( utils.getAge( new Date(), null, DateUnit.DAYS ) ); + } + + @Test + public void getYoungerThanRelative() + { + final GregorianCalendar cal1 = new GregorianCalendar( 2017, Calendar.JUNE, 8, 15, 16, 17 ); + final GregorianCalendar cal2 = new GregorianCalendar( 2017, Calendar.JUNE, 6, 14, 16, 17 ); + Assert.assertTrue( utils.isYoungerThan( new DateTimeType( cal1.getTime() ), cal2.getTime(), 3, DateUnit.DAYS ) ); + } + + @Test + public void getNotYoungerThanRelative() + { + final GregorianCalendar cal1 = new GregorianCalendar( 2017, Calendar.JUNE, 8, 15, 16, 17 ); + final GregorianCalendar cal2 = new GregorianCalendar( 2017, Calendar.JUNE, 6, 14, 16, 17 ); + Assert.assertFalse( utils.isYoungerThan( new DateTimeType( cal1.getTime() ), cal2.getTime(), 2, DateUnit.DAYS ) ); + } + + @Test + public void getYoungerThanToday() + { + Assert.assertTrue( utils.isYoungerThan( LocalDate.now().minusDays( 2 ), 3, DateUnit.DAYS ) ); + } + + @Test + public void getNotYoungerThanToday() + { + Assert.assertFalse( utils.isYoungerThan( LocalDate.now().minusDays( 2 ), 2, DateUnit.DAYS ) ); + } + + @Test + public void getAgeYoungerThanNull() + { + Assert.assertFalse( utils.isYoungerThan( new Date(), null, 3, DateUnit.DAYS ) ); + } + + @Test + public void getOlderThanRelative() + { + final GregorianCalendar cal1 = new GregorianCalendar( 2017, Calendar.JUNE, 8, 15, 16, 17 ); + final GregorianCalendar cal2 = new GregorianCalendar( 2017, Calendar.JUNE, 6, 14, 16, 17 ); + Assert.assertTrue( utils.isOlderThan( new DateTimeType( cal1.getTime() ), cal2.getTime(), 1, DateUnit.DAYS ) ); + } + + @Test + public void getNotOlderThanRelative() + { + final GregorianCalendar cal1 = new GregorianCalendar( 2017, Calendar.JUNE, 8, 15, 16, 17 ); + final GregorianCalendar cal2 = new GregorianCalendar( 2017, Calendar.JUNE, 6, 14, 16, 17 ); + Assert.assertFalse( utils.isOlderThan( new DateTimeType( cal1.getTime() ), cal2.getTime(), 2, DateUnit.DAYS ) ); + } + + @Test + public void getOlderThanToday() + { + Assert.assertTrue( utils.isOlderThan( LocalDate.now().minusDays( 2 ), 1, DateUnit.DAYS ) ); + } + + @Test + public void getNotOlderThanToday() + { + Assert.assertFalse( utils.isOlderThan( LocalDate.now().minusDays( 2 ), 2, DateUnit.DAYS ) ); + } + + @Test + public void getAgeOlderThanNull() + { + Assert.assertFalse( utils.isOlderThan( new Date(), null, 3, DateUnit.DAYS ) ); + } +} \ No newline at end of file diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4GeoFhirToDhisTransformerUtilsTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4GeoFhirToDhisTransformerUtilsTest.java new file mode 100644 index 00000000..63d974a0 --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4GeoFhirToDhisTransformerUtilsTest.java @@ -0,0 +1,85 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.geo.Location; +import org.hl7.fhir.r4.model.Address; +import org.hl7.fhir.r4.model.DecimalType; +import org.hl7.fhir.r4.model.Extension; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** + * Unit tests for {@link R4GeoFhirToDhisTransformerUtils}. + * + * @author volsch + */ +public class R4GeoFhirToDhisTransformerUtilsTest +{ + @Mock + private ScriptExecutionContext scriptExecutionContext; + + @InjectMocks + private R4GeoFhirToDhisTransformerUtils utils; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Test + public void getLocation() + { + final Address address = new Address(); + address.addExtension() + .setUrl( "http://hl7.org/fhir/StructureDefinition/geolocation" ) + .addExtension( new Extension() + .setUrl( "latitude" ) + .setValue( new DecimalType( 8.4665341 ) ) ) + .addExtension( new Extension() + .setUrl( "longitude" ) + .setValue( new DecimalType( -13.262743 ) ) ); + final Location location = utils.getLocation( address ); + Assert.assertNotNull( location ); + Assert.assertEquals( 8.4665341, location.getLatitude(), 0 ); + Assert.assertEquals( -13.262743, location.getLongitude(), 0 ); + } + + @Test + public void getNoLocation() + { + final Address address = new Address(); + final Location location = utils.getLocation( address ); + Assert.assertNull( location ); + } +} \ No newline at end of file diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4HumanNameFhirToDhisTransformerUtilsTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4HumanNameFhirToDhisTransformerUtilsTest.java new file mode 100644 index 00000000..4d978ba0 --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4HumanNameFhirToDhisTransformerUtilsTest.java @@ -0,0 +1,151 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.hl7.fhir.r4.model.HumanName; +import org.hl7.fhir.r4.model.Period; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Unit tests for {@link R4HumanNameFhirToDhisTransformerUtils}. + * + * @author volsch + */ +public class R4HumanNameFhirToDhisTransformerUtilsTest +{ + @Mock + private ScriptExecutionContext scriptExecutionContext; + + @InjectMocks + private R4DateTimeFhirToDhisTransformerUtils dateTimeFhirToDhisTransformerUtils; + + private R4HumanNameFhirToDhisTransformerUtils utils; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Before + public void before() + { + utils = new R4HumanNameFhirToDhisTransformerUtils( scriptExecutionContext, dateTimeFhirToDhisTransformerUtils ); + } + + @Test + public void primaryExpired() + { + final List humanNames = new ArrayList<>(); + humanNames.add( new HumanName().setUse( HumanName.NameUse.OFFICIAL ) + .setPeriod( new Period().setEnd( Date.from( ZonedDateTime.now().minusDays( 1 ).toInstant() ) ) ) ); + humanNames.add( new HumanName().setUse( HumanName.NameUse.OLD ) ); + Assert.assertEquals( humanNames.get( 1 ), utils.getPrimaryName( humanNames ) ); + } + + @Test + public void primaryMaiden() + { + final List humanNames = new ArrayList<>(); + humanNames.add( new HumanName().setUse( HumanName.NameUse.MAIDEN ) ); + humanNames.add( new HumanName().setUse( HumanName.NameUse.OLD ) ); + Assert.assertEquals( humanNames.get( 0 ), utils.getPrimaryName( humanNames ) ); + } + + @Test + public void primaryTemp() + { + final List humanNames = new ArrayList<>(); + humanNames.add( new HumanName().setUse( HumanName.NameUse.TEMP ) ); + humanNames.add( new HumanName().setUse( HumanName.NameUse.MAIDEN ) ); + Assert.assertEquals( humanNames.get( 0 ), utils.getPrimaryName( humanNames ) ); + } + + @Test + public void primaryNickname() + { + final List humanNames = new ArrayList<>(); + humanNames.add( new HumanName().setUse( HumanName.NameUse.NICKNAME ) ); + humanNames.add( new HumanName().setUse( HumanName.NameUse.TEMP ) ); + Assert.assertEquals( humanNames.get( 0 ), utils.getPrimaryName( humanNames ) ); + } + + @Test + public void primaryAnonymous() + { + final List humanNames = new ArrayList<>(); + humanNames.add( new HumanName().setUse( HumanName.NameUse.ANONYMOUS ) ); + humanNames.add( new HumanName().setUse( HumanName.NameUse.NICKNAME ) ); + Assert.assertEquals( humanNames.get( 0 ), utils.getPrimaryName( humanNames ) ); + } + + @Test + public void primaryUsual() + { + final List humanNames = new ArrayList<>(); + humanNames.add( new HumanName().setUse( HumanName.NameUse.USUAL ) ); + humanNames.add( new HumanName().setUse( HumanName.NameUse.ANONYMOUS ) ); + Assert.assertEquals( humanNames.get( 0 ), utils.getPrimaryName( humanNames ) ); + } + + @Test + public void primaryNull() + { + final List humanNames = new ArrayList<>(); + humanNames.add( new HumanName().setUse( HumanName.NameUse.NULL ) ); + humanNames.add( new HumanName().setUse( HumanName.NameUse.ANONYMOUS ) ); + Assert.assertEquals( humanNames.get( 0 ), utils.getPrimaryName( humanNames ) ); + } + + @Test + public void primaryOther() + { + final List humanNames = new ArrayList<>(); + humanNames.add( new HumanName() ); + humanNames.add( new HumanName().setUse( HumanName.NameUse.ANONYMOUS ) ); + Assert.assertEquals( humanNames.get( 0 ), utils.getPrimaryName( humanNames ) ); + } + + @Test + public void primaryNothing() + { + final List humanNames = new ArrayList<>(); + Assert.assertNotNull( utils.getPrimaryName( humanNames ) ); + } +} \ No newline at end of file diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4IdentifierFhirToDhisTransformerUtilsTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4IdentifierFhirToDhisTransformerUtilsTest.java new file mode 100644 index 00000000..99d7ee8e --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4IdentifierFhirToDhisTransformerUtilsTest.java @@ -0,0 +1,163 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.fhir.metadata.model.FhirResourceType; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecution; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.FhirToDhisTransformerContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.ReferenceFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.fhir.transform.fhir.model.FhirRequest; +import org.dhis2.fhir.adapter.fhir.transform.fhir.model.ResourceSystem; +import org.dhis2.fhir.adapter.fhir.transform.util.FhirIdentifierUtils; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.Reference; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.Map; +import java.util.Optional; + +/** + * Unit tests for {@link R4IdentifierFhirToDhisTransformerUtils}. + * + * @author volsch + */ +public class R4IdentifierFhirToDhisTransformerUtilsTest +{ + @Mock + private ScriptExecutionContext scriptExecutionContext; + + @Mock + private ReferenceFhirToDhisTransformerUtils referenceFhirToDhisTransformerUtils; + + @Mock + private FhirToDhisTransformerContext context; + + @Mock + private FhirRequest request; + + @Mock + private ScriptExecution scriptExecution; + + @Mock + private Map variables; + + private final FhirIdentifierUtils fhirIdentifierUtils = new FhirIdentifierUtils(); + + private R4IdentifierFhirToDhisTransformerUtils utils; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Before + public void before() + { + utils = new R4IdentifierFhirToDhisTransformerUtils( scriptExecutionContext, fhirIdentifierUtils, referenceFhirToDhisTransformerUtils ); + } + + @Test + public void getReferenceIdentifierWithSystemNull() + { + Assert.assertNull( utils.getReferenceIdentifier( null, "PATIENT", "http://test.com" ) ); + } + + @Test + public void getReferenceIdentifierWithSystem() + { + final Patient patient = new Patient(); + patient.addIdentifier().setSystem( "http://test.com" ).setValue( "ABC_123" ); + final Reference reference = new Reference( new IdType( "Patient", "5671" ) ); + Mockito.doAnswer( invocation -> { + ((Reference) invocation.getArgument( 0 )).setResource( patient ); + return null; + } ).when( referenceFhirToDhisTransformerUtils ).initReference( Mockito.same( reference ), Mockito.eq( "PATIENT" ) ); + Assert.assertEquals( "ABC_123", utils.getReferenceIdentifier( reference, "PATIENT", "http://test.com" ) ); + Mockito.verify( referenceFhirToDhisTransformerUtils ).initReference( Mockito.same( reference ), Mockito.eq( "PATIENT" ) ); + } + + @Test + public void getReferenceIdentifierWithDifferentSystem() + { + final Patient patient = new Patient(); + patient.addIdentifier().setSystem( "http://test.com" ).setValue( "ABC_123" ); + final Reference reference = new Reference( new IdType( "Patient", "5671" ) ); + Mockito.doAnswer( invocation -> { + ((Reference) invocation.getArgument( 0 )).setResource( patient ); + return null; + } ).when( referenceFhirToDhisTransformerUtils ).initReference( Mockito.same( reference ), Mockito.eq( "PATIENT" ) ); + Assert.assertNull( utils.getReferenceIdentifier( reference, "PATIENT", "http://test2.com" ) ); + Mockito.verify( referenceFhirToDhisTransformerUtils ).initReference( Mockito.same( reference ), Mockito.eq( "PATIENT" ) ); + } + + @Test + public void getReferenceIdentifierWithDefaultSystem() + { + final Patient patient = new Patient(); + patient.addIdentifier().setSystem( "http://test.com" ).setValue( "ABC_123" ); + + final ResourceSystem resourceSystem = new ResourceSystem( FhirResourceType.PATIENT, "http://test.com", null, null, null ); + Mockito.doReturn( scriptExecution ).when( scriptExecutionContext ).getScriptExecution(); + Mockito.doReturn( variables ).when( scriptExecution ).getVariables(); + Mockito.doReturn( context ).when( variables ).get( Mockito.eq( "context" ) ); + Mockito.doReturn( request ).when( context ).getFhirRequest(); + Mockito.doReturn( Optional.of( resourceSystem ) ).when( request ).getOptionalResourceSystem( FhirResourceType.PATIENT ); + + final Reference reference = new Reference( new IdType( "Patient", "5671" ) ); + Mockito.doAnswer( invocation -> { + ((Reference) invocation.getArgument( 0 )).setResource( patient ); + return null; + } ).when( referenceFhirToDhisTransformerUtils ).initReference( Mockito.same( reference ), Mockito.eq( "PATIENT" ) ); + Assert.assertEquals( "ABC_123", utils.getReferenceIdentifier( reference, "PATIENT" ) ); + Mockito.verify( referenceFhirToDhisTransformerUtils ).initReference( Mockito.same( reference ), Mockito.eq( "PATIENT" ) ); + } + + @Test + public void getResourceIdentifierWithDefaultSystem() + { + final Patient patient = new Patient(); + patient.addIdentifier().setSystem( "http://test.com" ).setValue( "ABC_123" ); + + final ResourceSystem resourceSystem = new ResourceSystem( FhirResourceType.PATIENT, "http://test.com", null, null, null ); + Mockito.doReturn( scriptExecution ).when( scriptExecutionContext ).getScriptExecution(); + Mockito.doReturn( variables ).when( scriptExecution ).getVariables(); + Mockito.doReturn( context ).when( variables ).get( Mockito.eq( "context" ) ); + Mockito.doReturn( request ).when( context ).getFhirRequest(); + Mockito.doReturn( Optional.of( resourceSystem ) ).when( request ).getOptionalResourceSystem( FhirResourceType.PATIENT ); + + Assert.assertEquals( "ABC_123", utils.getResourceIdentifier( patient, "PATIENT" ) ); + } +} \ No newline at end of file diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4OrganizationFhirToDhisTransformerUtilsTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4OrganizationFhirToDhisTransformerUtilsTest.java new file mode 100644 index 00000000..8ec5cf60 --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4OrganizationFhirToDhisTransformerUtilsTest.java @@ -0,0 +1,206 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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.context.FhirContext; +import org.dhis2.fhir.adapter.dhis.model.Reference; +import org.dhis2.fhir.adapter.dhis.model.ReferenceType; +import org.dhis2.fhir.adapter.dhis.orgunit.OrganizationUnit; +import org.dhis2.fhir.adapter.dhis.orgunit.OrganizationUnitService; +import org.dhis2.fhir.adapter.fhir.metadata.model.FhirResourceType; +import org.dhis2.fhir.adapter.fhir.metadata.model.FhirServer; +import org.dhis2.fhir.adapter.fhir.metadata.model.FhirServerResource; +import org.dhis2.fhir.adapter.fhir.metadata.model.SubscriptionFhirEndpoint; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirServerResourceRepository; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.repository.FhirResourceRepository; +import org.dhis2.fhir.adapter.fhir.repository.HierarchicallyFhirResourceRepository; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecution; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.FhirToDhisTransformerContext; +import org.dhis2.fhir.adapter.fhir.transform.fhir.model.FhirRequest; +import org.dhis2.fhir.adapter.fhir.transform.fhir.model.ResourceSystem; +import org.hl7.fhir.instance.model.api.IBaseReference; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Organization; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Function; + +/** + * Unit tests for {@link R4OrganizationFhirToDhisTransformerUtils}. + * + * @author volsch + */ +public class R4OrganizationFhirToDhisTransformerUtilsTest +{ + @Mock + private ScriptExecutionContext scriptExecutionContext; + + @Mock + private OrganizationUnitService organizationUnitService; + + @Mock + private FhirServerResourceRepository fhirServerResourceRepository; + + @Mock + private FhirResourceRepository fhirResourceRepository; + + @Mock + private HierarchicallyFhirResourceRepository hierarchicallyFhirResourceRepository; + + @Mock + private FhirToDhisTransformerContext context; + + @Mock + private FhirRequest request; + + @Mock + private ScriptExecution scriptExecution; + + @Mock + private Map variables; + + @InjectMocks + private R4OrganizationFhirToDhisTransformerUtils utils; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Test + public void exists() + { + Mockito.doReturn( Optional.of( new OrganizationUnit() ) ).when( organizationUnitService ).findOneByReference( Mockito.eq( new Reference( "ABC_123", ReferenceType.CODE ) ) ); + Assert.assertTrue( utils.exists( "ABC_123" ) ); + Mockito.verify( organizationUnitService ).findOneByReference( Mockito.eq( new Reference( "ABC_123", ReferenceType.CODE ) ) ); + } + + @Test + public void existsNot() + { + Mockito.doReturn( Optional.empty() ).when( organizationUnitService ).findOneByReference( Mockito.eq( new Reference( "ABC_123", ReferenceType.CODE ) ) ); + Assert.assertFalse( utils.exists( "ABC_123" ) ); + Mockito.verify( organizationUnitService ).findOneByReference( Mockito.eq( new Reference( "ABC_123", ReferenceType.CODE ) ) ); + } + + @Test + public void existsWithPrefix() + { + final ResourceSystem resourceSystem = new ResourceSystem( FhirResourceType.ORGANIZATION, "http://test.com", "OT_", null, null ); + Mockito.doReturn( scriptExecution ).when( scriptExecutionContext ).getScriptExecution(); + Mockito.doReturn( variables ).when( scriptExecution ).getVariables(); + Mockito.doReturn( context ).when( variables ).get( Mockito.eq( "context" ) ); + Mockito.doReturn( request ).when( context ).getFhirRequest(); + Mockito.doReturn( Optional.of( resourceSystem ) ).when( request ).getOptionalResourceSystem( FhirResourceType.ORGANIZATION ); + + + Mockito.doReturn( Optional.of( new OrganizationUnit() ) ).when( organizationUnitService ).findOneByReference( Mockito.eq( new Reference( "OT_ABC_123", ReferenceType.CODE ) ) ); + Assert.assertEquals( "OT_ABC_123", utils.existsWithPrefix( "ABC_123" ) ); + Mockito.verify( organizationUnitService ).findOneByReference( Mockito.eq( new Reference( "OT_ABC_123", ReferenceType.CODE ) ) ); + } + + @Test + public void existsNotWithPrefix() + { + final ResourceSystem resourceSystem = new ResourceSystem( FhirResourceType.ORGANIZATION, "http://test.com", "OT_", null, null ); + Mockito.doReturn( scriptExecution ).when( scriptExecutionContext ).getScriptExecution(); + Mockito.doReturn( variables ).when( scriptExecution ).getVariables(); + Mockito.doReturn( context ).when( variables ).get( Mockito.eq( "context" ) ); + Mockito.doReturn( request ).when( context ).getFhirRequest(); + Mockito.doReturn( Optional.of( resourceSystem ) ).when( request ).getOptionalResourceSystem( FhirResourceType.ORGANIZATION ); + + Mockito.doReturn( Optional.empty() ).when( organizationUnitService ).findOneByReference( Mockito.eq( new Reference( "OT_ABC_123", ReferenceType.CODE ) ) ); + Assert.assertNull( utils.existsWithPrefix( "ABC_123" ) ); + Mockito.verify( organizationUnitService ).findOneByReference( Mockito.eq( new Reference( "OT_ABC_123", ReferenceType.CODE ) ) ); + } + + @Test + public void findHierarchy() + { + final SubscriptionFhirEndpoint subscriptionFhirEndpoint = new SubscriptionFhirEndpoint(); + final FhirServer fhirServer = new FhirServer(); + fhirServer.setFhirEndpoint( subscriptionFhirEndpoint ); + final FhirContext fhirContext = FhirContext.forR4(); + final UUID fhirServerResourceId = UUID.randomUUID(); + final FhirServerResource fhirServerResource = new FhirServerResource(); + fhirServerResource.setFhirServer( fhirServer ); + final ResourceSystem resourceSystem = new ResourceSystem( FhirResourceType.ORGANIZATION, "http://test.com", "OT_", null, null ); + Mockito.doReturn( scriptExecution ).when( scriptExecutionContext ).getScriptExecution(); + Mockito.doReturn( variables ).when( scriptExecution ).getVariables(); + Mockito.doReturn( context ).when( variables ).get( Mockito.eq( "context" ) ); + Mockito.doReturn( request ).when( context ).getFhirRequest(); + Mockito.doReturn( fhirServerResourceId ).when( request ).getFhirServerResourceId(); + Mockito.doReturn( FhirVersion.R4 ).when( request ).getVersion(); + Mockito.doReturn( Optional.of( resourceSystem ) ).when( request ).getOptionalResourceSystem( FhirResourceType.ORGANIZATION ); + Mockito.doReturn( Optional.of( fhirServerResource ) ).when( fhirServerResourceRepository ).findOneByIdCached( Mockito.eq( fhirServerResourceId ) ); + Mockito.doReturn( Optional.of( fhirContext ) ).when( fhirResourceRepository ).findFhirContext( Mockito.eq( FhirVersion.R4 ) ); + + final Organization org1 = (Organization) new Organization().setId( new IdType( "Organization", "1" ) ); + final Organization org2 = (Organization) new Organization().setId( new IdType( "2" ) ); + final Organization org3 = (Organization) new Organization().setId( new IdType( ("3") ) ); + final Organization org4 = (Organization) new Organization().setId( new IdType( "Organization", "4" ) ); + + Mockito.doAnswer( invocation -> { + final Function parentReferenceFunction = invocation.getArgument( 6 ); + Assert.assertEquals( org3.getPartOf(), parentReferenceFunction.apply( org3 ) ); + Assert.assertEquals( org4.getPartOf(), parentReferenceFunction.apply( org4 ) ); + return new Bundle() + .addEntry( new Bundle.BundleEntryComponent().setResource( org3 ) ) + .addEntry( new Bundle.BundleEntryComponent().setResource( org4 ) ); + } ) + .when( hierarchicallyFhirResourceRepository ) + .findWithParents( Mockito.eq( fhirServerResourceId ), Mockito.eq( FhirVersion.R4 ), Mockito.same( subscriptionFhirEndpoint ), + Mockito.eq( "Organization" ), Mockito.eq( "3" ), Mockito.eq( "organizationPartOf" ), Mockito.any() ); + + final org.hl7.fhir.r4.model.Reference org2Ref = new org.hl7.fhir.r4.model.Reference( org2.getIdElement() ); + org2Ref.setResource( org2 ); + org1.setPartOf( org2Ref ); + org2.setPartOf( new org.hl7.fhir.r4.model.Reference( org3.getIdElement() ) ); + org3.setPartOf( new org.hl7.fhir.r4.model.Reference( org4.getIdElement() ) ); + + final org.hl7.fhir.r4.model.Reference org1Ref = new org.hl7.fhir.r4.model.Reference( org1.getIdElement() ); + org1Ref.setResource( org1 ); + + final List hierarchy = utils.findHierarchy( org1Ref ); + + } +} \ No newline at end of file diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4PatientFhirToDhisTransformerUtilsTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4PatientFhirToDhisTransformerUtilsTest.java new file mode 100644 index 00000000..0eedbce9 --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4PatientFhirToDhisTransformerUtilsTest.java @@ -0,0 +1,72 @@ +package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.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 org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.hl7.fhir.r4.model.Address; +import org.hl7.fhir.r4.model.Patient; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** + * Unit tests for {@link R4PatientFhirToDhisTransformerUtils}. + * + * @author volsch + */ +public class R4PatientFhirToDhisTransformerUtilsTest +{ + @Mock + private ScriptExecutionContext scriptExecutionContext; + + @InjectMocks + private R4PatientFhirToDhisTransformerUtils utils; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Test + public void nullPatient() + { + Assert.assertNull( utils.getBirthPlaceAddress( null ) ); + } + + @Test + public void validAddress() + { + final Address address = new Address().setText( "Hospital" ); + final Patient patient = new Patient(); + patient.addExtension().setUrl( "http://hl7.org/fhir/StructureDefinition/birthPlace" ).setValue( address ); + Assert.assertSame( address, utils.getBirthPlaceAddress( patient ) ); + } +} \ No newline at end of file diff --git a/fhir-r4/src/test/resources/logback-test.xml b/fhir-r4/src/test/resources/logback-test.xml new file mode 100644 index 00000000..b9b017dd --- /dev/null +++ b/fhir-r4/src/test/resources/logback-test.xml @@ -0,0 +1,33 @@ + + + + + + + diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/FhirResourceType.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/FhirResourceType.java index 36a833bb..935fdd6d 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/FhirResourceType.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/FhirResourceType.java @@ -63,7 +63,9 @@ public enum FhirResourceType OBSERVATION( "Observation", 20, "Observation" ), ORGANIZATION( "Organization", 1, "Organization" ), PATIENT( "Patient", 10, "Patient" ), - RELATED_PERSON( "RelatedPerson", 11, "RelatedPerson" ); + RELATED_PERSON( "RelatedPerson", 11, "RelatedPerson" ), + PRACTITIONER( "Practitioner", 9, "Practitioner" ), + ; private static final Map resourcesBySimpleClassName = Arrays.stream( values() ).flatMap( v -> v.getSimpleClassNames().stream().map( scn -> new SimpleEntry<>( scn, v ) ) ) .collect( Collectors.toMap( SimpleEntry::getKey, SimpleEntry::getValue ) ); diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/model/FhirVersion.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/model/FhirVersion.java index 0b40b17e..04404563 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/model/FhirVersion.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/model/FhirVersion.java @@ -1,7 +1,7 @@ package org.dhis2.fhir.adapter.fhir.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 @@ -44,12 +44,15 @@ */ public enum FhirVersion { - DSTU3( FhirVersionEnum.DSTU3 ); + DSTU3( FhirVersionEnum.DSTU3 ), + R4( FhirVersionEnum.R4 ); public static final Set ALL = Collections.unmodifiableSet( new HashSet<>( Arrays.asList( FhirVersion.values() ) ) ); public static final Set DSTU3_ONLY = Collections.singleton( DSTU3 ); + public static final Set R4_ONLY = Collections.singleton( R4 ); + @Nullable public static FhirVersion get( @Nullable FhirVersionEnum fhirVersionEnum ) { diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/AbstractFhirResourceRepositorySupport.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/AbstractFhirResourceRepositorySupport.java new file mode 100644 index 00000000..d7c1db85 --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/AbstractFhirResourceRepositorySupport.java @@ -0,0 +1,78 @@ +package org.dhis2.fhir.adapter.fhir.repository.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.fhir.metadata.model.FhirServerResource; +import org.dhis2.fhir.adapter.fhir.model.FhirVersionRestricted; +import org.hl7.fhir.instance.model.api.IAnyResource; +import org.hl7.fhir.instance.model.api.IBaseBundle; +import org.hl7.fhir.instance.model.api.IBaseResource; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.UUID; + +/** + * Abstract FHIR version dependent base class for FHIR resource repository utils. + * + * @author volsch + */ +public abstract class AbstractFhirResourceRepositorySupport implements FhirVersionRestricted +{ + @Nonnull + protected abstract AbstractFhirRepositoryResourceUtils createFhirRepositoryResourceUtils( @Nonnull UUID fhirServerId ); + + @Nonnull + protected abstract IAnyResource createFhirSubscription( @Nonnull FhirServerResource fhirServerResource ); + + @Nullable + protected abstract IBaseResource getFirstResource( @Nonnull IBaseBundle bundle ); + + @Nonnull + protected abstract Class getBundleClass(); + + @Nonnull + protected abstract IBaseBundle createBundle( @Nonnull List resources ); + + @Nonnull + protected String createWebHookUrl( @Nonnull FhirServerResource fhirServerResource ) + { + final StringBuilder url = new StringBuilder( fhirServerResource.getFhirServer().getAdapterEndpoint().getBaseUrl() ); + if ( url.charAt( url.length() - 1 ) != '/' ) + { + url.append( '/' ); + } + url.append( "remote-fhir-rest-hook/" ); + url.append( fhirServerResource.getFhirServer().getId() ); + url.append( '/' ); + url.append( fhirServerResource.getId() ); + return url.toString(); + } +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/AbstractFhirResourceRepositoryImpl.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/FhirResourceRepositoryImpl.java similarity index 90% rename from fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/AbstractFhirResourceRepositoryImpl.java rename to fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/FhirResourceRepositoryImpl.java index 077e295c..954f7f76 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/AbstractFhirResourceRepositoryImpl.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/FhirResourceRepositoryImpl.java @@ -59,7 +59,6 @@ import org.dhis2.fhir.adapter.fhir.server.StoredFhirResourceService; import org.dhis2.fhir.adapter.rest.RestBadRequestException; import org.dhis2.fhir.adapter.util.NameUtils; -import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseResource; import org.slf4j.Logger; @@ -69,6 +68,7 @@ import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Component; import org.springframework.transaction.event.TransactionPhase; import org.springframework.transaction.event.TransactionalEventListener; @@ -88,8 +88,9 @@ * * @author volsch */ +@Component @CacheConfig( cacheNames = "fhirResources", cacheManager = "fhirCacheManager" ) -public abstract class AbstractFhirResourceRepositoryImpl implements FhirResourceRepository +public class FhirResourceRepositoryImpl implements FhirResourceRepository { private final Logger logger = LoggerFactory.getLogger( getClass() ); @@ -101,22 +102,19 @@ public abstract class AbstractFhirResourceRepositoryImpl implements FhirResource private final Map fhirContexts; - public AbstractFhirResourceRepositoryImpl( @Nonnull ScriptExecutor scriptExecutor, @Nonnull StoredFhirResourceService storedItemService, @Nonnull FhirServerResourceRepository fhirServerResourceRepository, - @Nonnull ObjectProvider> fhirContexts ) + private final Map supports = new HashMap<>(); + + public FhirResourceRepositoryImpl( @Nonnull ScriptExecutor scriptExecutor, @Nonnull StoredFhirResourceService storedItemService, @Nonnull FhirServerResourceRepository fhirServerResourceRepository, + @Nonnull ObjectProvider> fhirContexts, @Nonnull ObjectProvider> supports ) { this.scriptExecutor = scriptExecutor; this.storedItemService = storedItemService; this.fhirServerResourceRepository = fhirServerResourceRepository; this.fhirContexts = fhirContexts.getIfAvailable( Collections::emptyList ).stream().filter( fc -> (FhirVersion.get( fc.getVersion().getVersion() ) != null) ) .collect( Collectors.toMap( fc -> FhirVersion.get( fc.getVersion().getVersion() ), fc -> fc ) ); + supports.getIfAvailable( Collections::emptyList ).forEach( s -> s.getFhirVersions().forEach( v -> FhirResourceRepositoryImpl.this.supports.put( v, s ) ) ); } - @Nonnull - protected abstract AbstractFhirRepositoryResourceUtils createFhirRepositoryResourceUtils( @Nonnull UUID fhirServerId ); - - @Nonnull - protected abstract IAnyResource createFhirSubscription( @Nonnull FhirServerResource fhirServerResource ); - @Nonnull @Override public Optional findFhirContext( @Nonnull FhirVersion fhirVersion ) @@ -214,9 +212,10 @@ public IBaseResource transform( @Nonnull UUID fhirServerId, @Nonnull FhirVersion final Optional fhirServerResource = fhirServerResourceRepository.findFirstCached( fhirServerId, fhirResourceType ); if ( fhirServerResource.isPresent() && (fhirServerResource.get().getImpTransformScript() != null) ) { + final AbstractFhirResourceRepositorySupport support = supports.get( fhirVersion ); final Map variables = new HashMap<>(); variables.put( ScriptVariable.RESOURCE.getVariableName(), resource ); - variables.put( ScriptVariable.UTILS.getVariableName(), createFhirRepositoryResourceUtils( fhirServerId ) ); + variables.put( ScriptVariable.UTILS.getVariableName(), support.createFhirRepositoryResourceUtils( fhirServerId ) ); try { @@ -329,13 +328,15 @@ else if ( (methodOutcome.getId() != null) && methodOutcome.getId().hasVersionIdP @TransactionalEventListener( phase = TransactionPhase.BEFORE_COMMIT, classes = AutoCreatedFhirServerResourceEvent.class ) public void autoCreatedSubscriptionResource( @Nonnull AutoCreatedFhirServerResourceEvent event ) { - final FhirContext fhirContext = fhirContexts.get( event.getFhirServerResource().getFhirServer().getFhirVersion() ); + final FhirVersion fhirVersion = event.getFhirServerResource().getFhirServer().getFhirVersion(); + final FhirContext fhirContext = fhirContexts.get( fhirVersion ); final IGenericClient client = FhirClientUtils.createClient( fhirContext, event.getFhirServerResource().getFhirServer().getFhirEndpoint() ); + final AbstractFhirResourceRepositorySupport support = supports.get( fhirVersion ); final MethodOutcome methodOutcome; try { - methodOutcome = client.create().resource( createFhirSubscription( event.getFhirServerResource() ) ).execute(); + methodOutcome = client.create().resource( support.createFhirSubscription( event.getFhirServerResource() ) ).execute(); } catch ( BaseServerResponseException e ) { @@ -347,38 +348,18 @@ public void autoCreatedSubscriptionResource( @Nonnull AutoCreatedFhirServerResou event.getFhirServerResource().setFhirSubscriptionId( id ); } - @Nonnull - protected String createWebHookUrl( @Nonnull FhirServerResource fhirServerResource ) - { - final StringBuilder url = new StringBuilder( fhirServerResource.getFhirServer().getAdapterEndpoint().getBaseUrl() ); - if ( url.charAt( url.length() - 1 ) != '/' ) - { - url.append( '/' ); - } - url.append( "remote-fhir-rest-hook/" ); - url.append( fhirServerResource.getFhirServer().getId() ); - url.append( '/' ); - url.append( fhirServerResource.getId() ); - return url.toString(); - } - - @Nullable - protected abstract IBaseResource getFirstResource( @Nonnull IBaseBundle bundle ); - - @Nonnull - protected abstract Class getBundleClass(); - @Nonnull protected Optional findByToken( @Nonnull UUID fhirServerId, @Nonnull FhirVersion fhirVersion, @Nonnull SubscriptionFhirEndpoint fhirEndpoint, @Nonnull String resourceType, @Nonnull String field, @Nonnull SystemCodeValue identifier ) { final FhirContext fhirContext = fhirContexts.get( fhirVersion ); final IGenericClient client = FhirClientUtils.createClient( fhirContext, fhirEndpoint ); + final AbstractFhirResourceRepositorySupport support = supports.get( fhirVersion ); logger.debug( "Reading {}?{}={} from FHIR endpoints {}.", resourceType, identifier, field, fhirEndpoint.getBaseUrl() ); - final IBaseBundle bundle = client.search().forResource( resourceType ).returnBundle( getBundleClass() ) + final IBaseBundle bundle = client.search().forResource( resourceType ).returnBundle( support.getBundleClass() ) .where( new TokenClientParam( field ).exactly().systemAndIdentifier( identifier.getSystem(), identifier.getCode() ) ) .cacheControl( new CacheControlDirective().setNoCache( true ) ).execute(); - final IBaseResource resource = getFirstResource( bundle ); + final IBaseResource resource = support.getFirstResource( bundle ); logger.debug( "Read {}?{}={} from FHIR endpoints {} (found={}).", resourceType, identifier, field, fhirEndpoint.getBaseUrl(), (resource != null) ); return Optional.ofNullable( transform( fhirServerId, fhirVersion, resource ) ); } diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/AbstractHierarchicallyFhirResourceRepositoryImpl.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/HierarchicallyFhirResourceRepositoryImpl.java similarity index 84% rename from fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/AbstractHierarchicallyFhirResourceRepositoryImpl.java rename to fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/HierarchicallyFhirResourceRepositoryImpl.java index b08bc739..77d2157e 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/AbstractHierarchicallyFhirResourceRepositoryImpl.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/HierarchicallyFhirResourceRepositoryImpl.java @@ -36,15 +36,19 @@ import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseReference; import org.hl7.fhir.instance.model.api.IBaseResource; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Component; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; @@ -55,14 +59,18 @@ * * @author volsch */ +@Component @CacheConfig( cacheNames = "hierarchicallyFhirResources", cacheManager = "fhirCacheManager" ) -public abstract class AbstractHierarchicallyFhirResourceRepositoryImpl implements HierarchicallyFhirResourceRepository +public class HierarchicallyFhirResourceRepositoryImpl implements HierarchicallyFhirResourceRepository { private final FhirResourceRepository fhirResourceRepository; - public AbstractHierarchicallyFhirResourceRepositoryImpl( @Nonnull FhirResourceRepository fhirResourceRepository ) + private final Map supports = new HashMap<>(); + + public HierarchicallyFhirResourceRepositoryImpl( @Nonnull FhirResourceRepository fhirResourceRepository, @Nonnull ObjectProvider> supports ) { this.fhirResourceRepository = fhirResourceRepository; + supports.getIfAvailable( Collections::emptyList ).forEach( s -> s.getFhirVersions().forEach( v -> HierarchicallyFhirResourceRepositoryImpl.this.supports.put( v, s ) ) ); } @Nonnull @@ -72,15 +80,16 @@ public IBaseBundle findWithParents( @Nonnull UUID fhirServerId, @Nonnull FhirVer @Nonnull String resourceType, @Nullable String resourceId, @Nonnull String hierarchyType, @Nonnull Function parentReferenceFunction ) { + final AbstractFhirResourceRepositorySupport support = supports.get( fhirVersion ); if ( resourceId == null ) { - return createBundle( Collections.emptyList() ); + return support.createBundle( Collections.emptyList() ); } IBaseResource child = fhirResourceRepository.find( fhirServerId, fhirVersion, fhirEndpoint, resourceType, resourceId ).orElse( null ); if ( child == null ) { - return createBundle( Collections.emptyList() ); + return support.createBundle( Collections.emptyList() ); } final Set processedResources = new HashSet<>(); @@ -119,9 +128,6 @@ public IBaseBundle findWithParents( @Nonnull UUID fhirServerId, @Nonnull FhirVer } } - return createBundle( result ); + return support.createBundle( result ); } - - @Nonnull - protected abstract IBaseBundle createBundle( @Nonnull List resources ); } diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/AbstractFhirResourceDhisToFhirTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/AbstractFhirResourceDhisToFhirTransformerUtils.java index bc91061a..7eedc0dd 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/AbstractFhirResourceDhisToFhirTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/AbstractFhirResourceDhisToFhirTransformerUtils.java @@ -37,6 +37,7 @@ import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.dhis2.fhir.adapter.util.EnumValueUtils; import org.hl7.fhir.instance.model.api.IBase; +import org.hl7.fhir.instance.model.api.IBaseElement; import org.hl7.fhir.instance.model.api.IBaseReference; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.ICompositeType; @@ -109,6 +110,9 @@ public IBaseResource createResource( @Nonnull Object fhirResourceType ) return createResource( resourceType.getResourceTypeName() ); } + @Nonnull + public abstract IBaseElement createType( @Nonnull String fhirType ); + @Nonnull public IBaseResource createResource( @Nonnull FhirResourceType fhirResourceType ) { diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/AbstractCodeFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/AbstractCodeFhirToDhisTransformerUtils.java index ff7b4057..c9fae084 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/AbstractCodeFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/AbstractCodeFhirToDhisTransformerUtils.java @@ -1,7 +1,7 @@ package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util; /* - * 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 @@ -136,19 +136,33 @@ public final String getScriptAttrName() returnDescription = "Returns if the code is included." ) public abstract boolean containsCode( @Nullable ICompositeType codeableConcept, @Nullable String system, @Nonnull String code ); + @SuppressWarnings( "unchecked" ) @ScriptMethod( description = "Returns if the specified codeable concept contains any combination of the specified list of system code values (type SystemCodeValue).", args = { @ScriptMethodArg( value = "codeableConcept", description = "The codeable concept that should be checked." ), @ScriptMethodArg( value = "systemCodeValues", description = "List of system code values that should be used for the check (type SystemCodeValue)." ), }, returnDescription = "Returns if any system code value is included." ) - public boolean containsAnyCode( @Nullable ICompositeType codeableConcept, @Nullable Collection systemCodeValues ) + public boolean containsAnyCode( @Nullable Object codeableConcept, @Nullable Collection systemCodeValues ) { if ( (codeableConcept == null) || (systemCodeValues == null) ) { return false; } - return systemCodeValues.stream().anyMatch( scv -> containsCode( codeableConcept, scv.getSystem(), scv.getCode() ) ); + final Collection codeableConcepts; + if ( codeableConcept instanceof ICompositeType ) + { + codeableConcepts = Collections.singletonList( (ICompositeType) codeableConcept ); + } + else if ( codeableConcept instanceof Collection ) + { + codeableConcepts = (Collection) codeableConcept; + } + else + { + throw new IllegalArgumentException( "Expected composite type: " + codeableConcept.getClass() ); + } + return systemCodeValues.stream().anyMatch( scv -> codeableConcepts.stream().anyMatch( cc -> containsCode( cc, scv.getSystem(), scv.getCode() ) ) ); } @ScriptMethod( description = "Returns a map where the key is each specified mapping code and the value is a list of system code values (type SystemCodeValue). " + diff --git a/fhir/src/main/resources/db/migration/production/V1.1.0.8_0_0__FHIR_Version_R4.sql b/fhir/src/main/resources/db/migration/production/V1.1.0.8_0_0__FHIR_Version_R4.sql new file mode 100644 index 00000000..3f8b06d6 --- /dev/null +++ b/fhir/src/main/resources/db/migration/production/V1.1.0.8_0_0__FHIR_Version_R4.sql @@ -0,0 +1,35 @@ +/* + * 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_version_enum VALUES('R4'); +INSERT INTO fhir_resource_type_enum VALUES('PRACTITIONER'); + +INSERT INTO fhir_script_source_version(script_source_id, fhir_version) +SELECT script_source_id, 'R4' FROM fhir_script_source_version WHERE fhir_version = 'DSTU3'; diff --git a/fhir/src/main/resources/db/migration/programs/child_programme/V1.1.0.8_100_0__Child__Programme_FHIR_Version_R4.sql b/fhir/src/main/resources/db/migration/programs/child_programme/V1.1.0.8_100_0__Child__Programme_FHIR_Version_R4.sql new file mode 100644 index 00000000..4261f6c0 --- /dev/null +++ b/fhir/src/main/resources/db/migration/programs/child_programme/V1.1.0.8_100_0__Child__Programme_FHIR_Version_R4.sql @@ -0,0 +1,56 @@ +/* + * 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 + +DELETE FROM fhir_script_source_version WHERE script_source_id='78b4af9b-c247-4290-abee-44983938b265' AND fhir_version='R4'; +INSERT INTO fhir_script_source (id, version, script_id, source_text, source_type) +VALUES ('43e49f59-67d6-4919-a808-6a35bc55e18c', 0, '33952dc7-bbf9-474d-8eaa-ab866a926da3', +'var result; +var doseGiven = input.getIntegerOptionValue(args[''dataElement''], 1, args[''optionValuePattern'']); +if (doseGiven == null) +{ + output.setNotGiven(true); + result = !output.getIdElement().isEmpty(); +} +else +{ + output.setVaccineCode(codeUtils.getRuleCodeableConcept()); + if (output.getVaccineCode().isEmpty()) + { + output.getVaccineCode().setText(dataElementUtils.getDataElementName(args[''dataElement''])); + } + output.setPrimarySource(input.isProvidedElsewhere(args[''dataElement'']) == false); + output.setNotGiven(false); + output.setProtocolApplied(null); + output.addProtocolApplied().setDoseNumber(fhirResourceUtils.createType(''positiveInt'').setValue(doseGiven)); + result = true; +} +result', 'JAVASCRIPT'); +INSERT INTO fhir_script_source_version (script_source_id, fhir_version) +VALUES ('43e49f59-67d6-4919-a808-6a35bc55e18c', 'R4'); diff --git a/pom.xml b/pom.xml index 3f1a11aa..bb652a08 100644 --- a/pom.xml +++ b/pom.xml @@ -48,6 +48,7 @@ dhis fhir fhir-dstu3 + fhir-r4 app @@ -231,6 +232,16 @@ hapi-fhir-validation-resources-dstu3 ${hapi-fhir.version} + + ca.uhn.hapi.fhir + hapi-fhir-structures-r4 + ${hapi-fhir.version} + + + ca.uhn.hapi.fhir + hapi-fhir-validation-resources-r4 + ${hapi-fhir.version} + org.apache.commons