diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImmutableOptionSet.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImmutableOptionSet.java
index f88fb968..b229d988 100644
--- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImmutableOptionSet.java
+++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImmutableOptionSet.java
@@ -1,7 +1,7 @@
package org.dhis2.fhir.adapter.dhis.model;
/*
- * Copyright (c) 2004-2018, University of Oslo
+ * Copyright (c) 2004-2019, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,10 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import java.io.Serializable;
import java.util.List;
+import java.util.Optional;
import java.util.stream.Collectors;
/**
@@ -77,4 +79,12 @@ public List getOptions()
{
return (delegate.getOptions() == null) ? null : delegate.getOptions().stream().map( ImmutableOption::new ).collect( Collectors.toList() );
}
+
+ @JsonIgnore
+ @Nonnull
+ @Override
+ public Optional getOptionalOptionByCode( @Nullable String code )
+ {
+ return delegate.getOptionalOptionByCode( code );
+ }
}
diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/OptionSet.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/OptionSet.java
index 74b7fd06..9740ba02 100644
--- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/OptionSet.java
+++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/OptionSet.java
@@ -1,7 +1,7 @@
package org.dhis2.fhir.adapter.dhis.model;
/*
- * Copyright (c) 2004-2018, University of Oslo
+ * Copyright (c) 2004-2019, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,10 @@
import org.dhis2.fhir.adapter.scriptable.Scriptable;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import java.util.List;
+import java.util.Optional;
/**
* Contains read-only access to a DHIS2 Option Set contains DHIS2 Options.
@@ -47,4 +50,13 @@ public interface OptionSet
String getName();
List extends Option> getOptions();
+
+ /**
+ * Returns the option for the specified code.
+ *
+ * @param code the code for which the option should be returned.
+ * @return the optional option.
+ */
+ @Nonnull
+ Optional getOptionalOptionByCode( @Nullable String code );
}
diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/WritableOptionSet.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/WritableOptionSet.java
index 1584b98e..db8eda35 100644
--- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/WritableOptionSet.java
+++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/WritableOptionSet.java
@@ -1,7 +1,7 @@
package org.dhis2.fhir.adapter.dhis.model;
/*
- * Copyright (c) 2004-2018, University of Oslo
+ * Copyright (c) 2004-2019, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,8 +28,15 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import java.io.Serializable;
import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
/**
* Writable implementation of {@link OptionSet} that can also be used for
@@ -47,6 +54,9 @@ public class WritableOptionSet implements OptionSet, Serializable
private List options;
+ @JsonIgnore
+ private transient volatile Map optionsByCode;
+
@Override
public String getId()
{
@@ -79,4 +89,21 @@ public void setOptions( List options )
{
this.options = options;
}
+
+ @Nonnull
+ @Override
+ public Optional getOptionalOptionByCode( @Nullable String code )
+ {
+ if ( code == null )
+ {
+ return Optional.empty();
+ }
+
+ if ( optionsByCode == null )
+ {
+ optionsByCode = options.stream().collect( Collectors.toMap( WritableOption::getCode, o -> o ) );
+ }
+
+ return Optional.ofNullable( optionsByCode.get( code ) );
+ }
}
diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/dstu3/Dstu3ValueTypeDhisToFhirTransformerUtils.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/dstu3/Dstu3ValueTypeDhisToFhirTransformerUtils.java
new file mode 100644
index 00000000..d4f07a97
--- /dev/null
+++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/dstu3/Dstu3ValueTypeDhisToFhirTransformerUtils.java
@@ -0,0 +1,135 @@
+package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.dstu3;
+
+/*
+ * Copyright (c) 2004-2019, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import ca.uhn.fhir.parser.DataFormatException;
+import org.dhis2.fhir.adapter.dhis.converter.ValueConverter;
+import org.dhis2.fhir.adapter.dhis.model.Option;
+import org.dhis2.fhir.adapter.dhis.model.OptionSet;
+import org.dhis2.fhir.adapter.dhis.model.WritableOption;
+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.dhis.impl.util.AbstractValueTypeDhisToFhirTransformerUtils;
+import org.dhis2.fhir.adapter.model.ValueType;
+import org.dhis2.fhir.adapter.scriptable.Scriptable;
+import org.hl7.fhir.dstu3.model.BooleanType;
+import org.hl7.fhir.dstu3.model.CodeableConcept;
+import org.hl7.fhir.dstu3.model.Coding;
+import org.hl7.fhir.dstu3.model.DateTimeType;
+import org.hl7.fhir.dstu3.model.DecimalType;
+import org.hl7.fhir.dstu3.model.IntegerType;
+import org.hl7.fhir.dstu3.model.StringType;
+import org.hl7.fhir.dstu3.model.TimeType;
+import org.hl7.fhir.instance.model.api.IBaseDatatype;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Set;
+
+/**
+ * DSTU3 specific implementation of {@link AbstractValueTypeDhisToFhirTransformerUtils}.
+ *
+ * @author volsch
+ */
+@Scriptable
+@Component
+public class Dstu3ValueTypeDhisToFhirTransformerUtils extends AbstractValueTypeDhisToFhirTransformerUtils
+{
+ public Dstu3ValueTypeDhisToFhirTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, @Nonnull ValueConverter valueConverter )
+ {
+ super( scriptExecutionContext, valueConverter );
+ }
+
+ @Nonnull
+ @Override
+ public Set getFhirVersions()
+ {
+ return FhirVersion.DSTU3_ONLY;
+ }
+
+ @Nullable
+ @Override
+ protected IBaseDatatype convert( @Nullable String dhisValue, @Nonnull ValueType valueType, @Nullable OptionSet optionSet )
+ {
+ if ( dhisValue == null )
+ {
+ return null;
+ }
+
+ if ( optionSet != null )
+ {
+ final Option option = optionSet.getOptionalOptionByCode( dhisValue ).orElseGet( () -> new WritableOption( dhisValue, dhisValue ) );
+
+ return new CodeableConcept().addCoding( new Coding().setCode( option.getCode() ).setDisplay( option.getName() ) );
+ }
+
+ try
+ {
+ switch ( valueType )
+ {
+ case TEXT:
+ case LONG_TEXT:
+ case EMAIL:
+ case LETTER:
+ case ORGANISATION_UNIT:
+ case PHONE_NUMBER:
+ case TRACKER_ASSOCIATE:
+ case URL:
+ case USERNAME:
+ return new StringType( dhisValue );
+ case INTEGER:
+ case INTEGER_POSITIVE:
+ case INTEGER_NEGATIVE:
+ case INTEGER_ZERO_OR_POSITIVE:
+ return new IntegerType( dhisValue );
+ case NUMBER:
+ case PERCENTAGE:
+ case UNIT_INTERVAL:
+ return new DecimalType( dhisValue );
+ case DATETIME:
+ case DATE:
+ case AGE:
+ return new DateTimeType( dhisValue );
+ case TIME:
+ return new TimeType( dhisValue );
+ case BOOLEAN:
+ case TRUE_ONLY:
+ return new BooleanType( dhisValue );
+ default:
+ throw new TransformerDataException( "Unsupported DHIS2 value type: " + valueType );
+ }
+ }
+ catch ( DataFormatException | IllegalArgumentException e )
+ {
+ throw new TransformerDataException( "Value with value type " + valueType + " could not be parsed for setting corresponding FHIR value: " + dhisValue, e );
+ }
+ }
+}
diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/dstu3/Dstu3ValueTypeFhirToDhisTransformerUtils.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/dstu3/Dstu3ValueTypeFhirToDhisTransformerUtils.java
new file mode 100644
index 00000000..f6d0c0ea
--- /dev/null
+++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/dstu3/Dstu3ValueTypeFhirToDhisTransformerUtils.java
@@ -0,0 +1,165 @@
+package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.dstu3;
+
+/*
+ * Copyright (c) 2004-2019, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import 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.fhir.impl.util.AbstractValueTypeFhirToDhisTransformerUtils;
+import org.dhis2.fhir.adapter.model.ValueType;
+import org.dhis2.fhir.adapter.scriptable.Scriptable;
+import org.hl7.fhir.dstu3.model.CodeableConcept;
+import org.hl7.fhir.dstu3.model.Coding;
+import org.hl7.fhir.dstu3.model.DateTimeType;
+import org.hl7.fhir.dstu3.model.TimeType;
+import org.hl7.fhir.instance.model.api.IBaseDatatype;
+import org.hl7.fhir.instance.model.api.IPrimitiveType;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Set;
+
+/**
+ * FHIR version DSTU3 implementation of {@link AbstractValueTypeFhirToDhisTransformerUtils}.
+ *
+ * @author volsch
+ */
+@Component
+@Scriptable
+public class Dstu3ValueTypeFhirToDhisTransformerUtils extends AbstractValueTypeFhirToDhisTransformerUtils
+{
+ public Dstu3ValueTypeFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext )
+ {
+ super( scriptExecutionContext );
+ }
+
+ @Nonnull
+ @Override
+ public Set getFhirVersions()
+ {
+ return FhirVersion.DSTU3_ONLY;
+ }
+
+ @Nullable
+ @Override
+ protected Object convert( @Nullable IBaseDatatype fhirValue, @Nonnull ValueType valueType )
+ {
+ if ( fhirValue == null )
+ {
+ return null;
+ }
+
+ switch ( valueType )
+ {
+ case TEXT:
+ case LONG_TEXT:
+ case EMAIL:
+ case LETTER:
+ case ORGANISATION_UNIT:
+ case PHONE_NUMBER:
+ case TRACKER_ASSOCIATE:
+ case URL:
+ case USERNAME:
+ if ( fhirValue instanceof IPrimitiveType )
+ {
+ return ( (IPrimitiveType) fhirValue ).getValueAsString();
+ }
+
+ if ( fhirValue instanceof CodeableConcept )
+ {
+ return getCode( (CodeableConcept) fhirValue );
+ }
+
+ break;
+ case INTEGER:
+ case INTEGER_POSITIVE:
+ case INTEGER_NEGATIVE:
+ case INTEGER_ZERO_OR_POSITIVE:
+ if ( fhirValue instanceof IPrimitiveType && ( (IPrimitiveType) fhirValue ).getValue() instanceof Integer )
+ {
+ return ( (IPrimitiveType) fhirValue ).getValueAsString();
+ }
+
+ if ( fhirValue instanceof CodeableConcept )
+ {
+ return getCode( (CodeableConcept) fhirValue );
+ }
+
+ break;
+ case NUMBER:
+ case PERCENTAGE:
+ case UNIT_INTERVAL:
+ if ( fhirValue instanceof IPrimitiveType && ( (IPrimitiveType) fhirValue ).getValue() instanceof Number )
+ {
+ return ( (IPrimitiveType) fhirValue ).getValueAsString();
+ }
+
+ break;
+ case DATETIME:
+ case DATE:
+ case AGE:
+ if ( fhirValue instanceof DateTimeType )
+ {
+ return DateTimeFormatter.ISO_LOCAL_DATE_TIME
+ .format( ( (DateTimeType) fhirValue ).getValue().toInstant().atZone( ZoneId.systemDefault() ).toLocalDateTime() );
+ }
+
+ break;
+ case TIME:
+ if ( fhirValue instanceof TimeType )
+ {
+ return ( (TimeType) fhirValue ).getValueAsString();
+ }
+
+ break;
+ case BOOLEAN:
+ case TRUE_ONLY:
+ if ( fhirValue instanceof IPrimitiveType && ( (IPrimitiveType) fhirValue ).getValue() instanceof Boolean )
+ {
+ return ( (IPrimitiveType) fhirValue ).getValueAsString();
+ }
+
+ break;
+ default:
+ throw new TransformerDataException( "Unsupported DHIS2 value type: " + valueType );
+ }
+
+ throw new TransformerDataException( "Unsupported FHIR type " + fhirValue.getClass().getSimpleName() + " for DHIS2 value type " + valueType );
+ }
+
+ @Nullable
+ protected String getCode( @Nonnull CodeableConcept codeableConcept )
+ {
+ return codeableConcept.getCoding().stream().filter( c -> c.getSystem() == null ).map( Coding::getCode )
+ .findFirst().orElseThrow( () -> new TransformerDataException( "Codeable concept does not include a code (system must not be set)." ) );
+ }
+}
diff --git a/fhir-dstu3/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/dstu3/Dstu3ValueTypeDhisToFhirTransformerUtilsTest.java b/fhir-dstu3/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/dstu3/Dstu3ValueTypeDhisToFhirTransformerUtilsTest.java
new file mode 100644
index 00000000..a0034da8
--- /dev/null
+++ b/fhir-dstu3/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/dstu3/Dstu3ValueTypeDhisToFhirTransformerUtilsTest.java
@@ -0,0 +1,185 @@
+package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.dstu3;
+
+/*
+ * Copyright (c) 2004-2019, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import org.dhis2.fhir.adapter.dhis.converter.ValueConverter;
+import org.dhis2.fhir.adapter.dhis.model.WritableOption;
+import org.dhis2.fhir.adapter.dhis.model.WritableOptionSet;
+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.hl7.fhir.dstu3.model.Base;
+import org.hl7.fhir.dstu3.model.BooleanType;
+import org.hl7.fhir.dstu3.model.CodeableConcept;
+import org.hl7.fhir.dstu3.model.Coding;
+import org.hl7.fhir.dstu3.model.DateTimeType;
+import org.hl7.fhir.dstu3.model.DecimalType;
+import org.hl7.fhir.dstu3.model.IntegerType;
+import org.hl7.fhir.dstu3.model.StringType;
+import org.hl7.fhir.dstu3.model.TimeType;
+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.Mockito;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.Collections;
+import java.util.Date;
+
+/**
+ * Unit tests for {@link Dstu3ValueTypeDhisToFhirTransformerUtils}.
+ *
+ * @author volsch
+ */
+public class Dstu3ValueTypeDhisToFhirTransformerUtilsTest
+{
+ @Mock
+ private ScriptExecutionContext scriptExecutionContext;
+
+ @Mock
+ private ValueConverter valueConverter;
+
+ @InjectMocks
+ private Dstu3ValueTypeDhisToFhirTransformerUtils utils;
+
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule().silent();
+
+ @Before
+ public void setUp()
+ {
+ Mockito.when( valueConverter.convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) ) )
+ .thenAnswer( invocation -> invocation.getArgument( 0 ) );
+ }
+
+ @Test
+ public void getFhirVersions()
+ {
+ Assert.assertEquals( FhirVersion.DSTU3_ONLY, utils.getFhirVersions() );
+ }
+
+ @Test
+ public void convertNull()
+ {
+ Assert.assertNull( utils.convert( null, "text", null ) );
+ }
+
+ @Test
+ public void convertText()
+ {
+ Assert.assertTrue( new StringType( "This is a test" ).equalsDeep( (Base) utils.convert( "This is a test", "text", null ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertUnsupportedType()
+ {
+ utils.convert( "This is a test", "image", null );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test
+ public void convertInteger()
+ {
+ Assert.assertTrue( new IntegerType( 29837 ).equalsDeep( (Base) utils.convert( "29837", "Integer", null ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertIntegerDataFormat()
+ {
+ utils.convert( "298x37", "Integer", null );
+ }
+
+ @Test
+ public void convertNumber()
+ {
+ Assert.assertTrue( new DecimalType( 29837.5 ).equalsDeep( (Base) utils.convert( "29837.5", "Number", null ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test
+ public void convertBoolean()
+ {
+ Assert.assertTrue( new BooleanType( true ).equalsDeep( (Base) utils.convert( "true", "BOOLEAN", null ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test
+ public void convertTime()
+ {
+ Assert.assertTrue( new TimeType( "17:48:12" ).equalsDeep( (Base) utils.convert( "17:48:12", "Time", null ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test
+ public void convertDateTime()
+ {
+ Assert.assertTrue( new DateTimeType( Date.from( ZonedDateTime.of( 2018, 7, 21, 17, 48, 12, 0, ZoneId.systemDefault() ).toInstant() ) )
+ .equalsDeep( (Base) utils.convert( "2018-07-21T17:48:12", "datetime", null ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test
+ public void convertOption()
+ {
+ final WritableOptionSet optionSet = new WritableOptionSet();
+ optionSet.setOptions( Collections.singletonList( new WritableOption( "test1", "Test 1" ) ) );
+
+ Assert.assertTrue( new CodeableConcept().addCoding( new Coding().setCode( "test1" ).setDisplay( "Test 1" ) )
+ .equalsDeep( (Base) utils.convert( "test1", "text", optionSet ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test
+ public void convertOptionNotFound()
+ {
+ final WritableOptionSet optionSet = new WritableOptionSet();
+ optionSet.setOptions( Collections.singletonList( new WritableOption( "test1", "Test 1" ) ) );
+
+ Assert.assertTrue( new CodeableConcept().addCoding( new Coding().setCode( "test2" ).setDisplay( "test2" ) )
+ .equalsDeep( (Base) utils.convert( "test2", "text", optionSet ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+}
\ No newline at end of file
diff --git a/fhir-dstu3/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/dstu3/Dstu3ValueTypeFhirToDhisTransformerUtilsTest.java b/fhir-dstu3/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/dstu3/Dstu3ValueTypeFhirToDhisTransformerUtilsTest.java
new file mode 100644
index 00000000..8218868b
--- /dev/null
+++ b/fhir-dstu3/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/dstu3/Dstu3ValueTypeFhirToDhisTransformerUtilsTest.java
@@ -0,0 +1,179 @@
+package org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.dstu3;
+
+/*
+ * Copyright (c) 2004-2019, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import 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.model.ValueType;
+import org.hl7.fhir.dstu3.model.BooleanType;
+import org.hl7.fhir.dstu3.model.CodeableConcept;
+import org.hl7.fhir.dstu3.model.Coding;
+import org.hl7.fhir.dstu3.model.DateTimeType;
+import org.hl7.fhir.dstu3.model.DecimalType;
+import org.hl7.fhir.dstu3.model.IntegerType;
+import org.hl7.fhir.dstu3.model.StringType;
+import org.hl7.fhir.dstu3.model.TimeType;
+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.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+
+/**
+ * Unit tests for {@link Dstu3ValueTypeFhirToDhisTransformerUtils}.
+ *
+ * @author volsch
+ */
+public class Dstu3ValueTypeFhirToDhisTransformerUtilsTest
+{
+ @Mock
+ private ScriptExecutionContext scriptExecutionContext;
+
+ @InjectMocks
+ private Dstu3ValueTypeFhirToDhisTransformerUtils utils;
+
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ @Test
+ public void getFhirVersions()
+ {
+ Assert.assertEquals( FhirVersion.DSTU3_ONLY, utils.getFhirVersions() );
+ }
+
+ @Test
+ public void convertNull()
+ {
+ Assert.assertNull( utils.convert( null, ValueType.TEXT ) );
+ }
+
+ @Test
+ public void convertText()
+ {
+ Assert.assertEquals( "Das ist ein Test!", utils.convert( new StringType( "Das ist ein Test!" ), "text" ) );
+ }
+
+ @Test
+ public void convertTextCode()
+ {
+ Assert.assertEquals( "test1", utils.convert( new CodeableConcept().addCoding( new Coding().setCode( "test1" ) ), "Text" ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertTextCodeWithSystem()
+ {
+ utils.convert( new CodeableConcept().addCoding( new Coding().setSystem( "abc" ).setCode( "test1" ) ), "text" );
+ }
+
+ @Test
+ public void convertInteger()
+ {
+ Assert.assertEquals( "736384", utils.convert( new IntegerType( 736384 ), "integer" ) );
+ }
+
+ @Test
+ public void convertIntegerCode()
+ {
+ Assert.assertEquals( "736384", utils.convert( new CodeableConcept().addCoding( new Coding().setCode( "736384" ) ), "integer" ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertIntegerInvalid()
+ {
+ utils.convert( new TimeType( "12:47:21" ), "integer" );
+ }
+
+ @Test
+ public void convertNumber()
+ {
+ Assert.assertEquals( "736384.5", utils.convert( new DecimalType( 736384.5 ), "number" ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertNumberInvalid()
+ {
+ utils.convert( new TimeType( "12:47:21" ), "Number" );
+ }
+
+ @Test
+ public void convertDateTime()
+ {
+ final LocalDateTime expected = ZonedDateTime.of( 2019, 7, 21, 16, 48, 12, 0, ZoneId.ofOffset( "UTC", ZoneOffset.ofHours( 7 ) ) )
+ .withZoneSameInstant( ZoneId.systemDefault() ).toLocalDateTime();
+
+ Assert.assertEquals( DateTimeFormatter.ISO_LOCAL_DATE_TIME.format( expected.atZone( ZoneId.systemDefault() ) ),
+ utils.convert( new DateTimeType( "2019-07-21T16:48:12+07:00" ), "datetime" ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertDateTimeInvalid()
+ {
+ utils.convert( new TimeType( "12:47:21" ), "datetime" );
+ }
+
+ @Test
+ public void convertTime()
+ {
+ Assert.assertEquals( "12:47:21", utils.convert( new TimeType( "12:47:21" ), "time" ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertTimeInvalid()
+ {
+ utils.convert( new DateTimeType( new Date() ), "time" );
+ }
+
+ @Test
+ public void convertBoolean()
+ {
+ Assert.assertEquals( "true", utils.convert( new BooleanType( true ), "boolean" ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertBooleanInvalid()
+ {
+ utils.convert( new DateTimeType( new Date() ), "boolean" );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertUnsupportedValueType()
+ {
+ utils.convert( new DateTimeType( new Date() ), "image" );
+ }
+}
\ No newline at end of file
diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4ValueTypeFhirToDhisTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4ValueTypeFhirToDhisTransformerUtils.java
new file mode 100644
index 00000000..3d6592b1
--- /dev/null
+++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4ValueTypeFhirToDhisTransformerUtils.java
@@ -0,0 +1,165 @@
+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.TransformerDataException;
+import org.dhis2.fhir.adapter.fhir.transform.fhir.impl.util.AbstractValueTypeFhirToDhisTransformerUtils;
+import org.dhis2.fhir.adapter.model.ValueType;
+import org.dhis2.fhir.adapter.scriptable.Scriptable;
+import org.hl7.fhir.instance.model.api.IBaseDatatype;
+import org.hl7.fhir.instance.model.api.IPrimitiveType;
+import org.hl7.fhir.r4.model.CodeableConcept;
+import org.hl7.fhir.r4.model.Coding;
+import org.hl7.fhir.r4.model.DateTimeType;
+import org.hl7.fhir.r4.model.TimeType;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Set;
+
+/**
+ * R4 specific implementation of {@link AbstractValueTypeFhirToDhisTransformerUtils}.
+ *
+ * @author volsch
+ */
+@Scriptable
+@Component
+public class R4ValueTypeFhirToDhisTransformerUtils extends AbstractValueTypeFhirToDhisTransformerUtils
+{
+ public R4ValueTypeFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext )
+ {
+ super( scriptExecutionContext );
+ }
+
+ @Nonnull
+ @Override
+ public Set getFhirVersions()
+ {
+ return FhirVersion.R4_ONLY;
+ }
+
+ @Nullable
+ @Override
+ protected Object convert( @Nullable IBaseDatatype fhirValue, @Nonnull ValueType valueType )
+ {
+ if ( fhirValue == null )
+ {
+ return null;
+ }
+
+ switch ( valueType )
+ {
+ case TEXT:
+ case LONG_TEXT:
+ case EMAIL:
+ case LETTER:
+ case ORGANISATION_UNIT:
+ case PHONE_NUMBER:
+ case TRACKER_ASSOCIATE:
+ case URL:
+ case USERNAME:
+ if ( fhirValue instanceof IPrimitiveType )
+ {
+ return ( (IPrimitiveType) fhirValue ).getValueAsString();
+ }
+
+ if ( fhirValue instanceof CodeableConcept )
+ {
+ return getCode( (CodeableConcept) fhirValue );
+ }
+
+ break;
+ case INTEGER:
+ case INTEGER_POSITIVE:
+ case INTEGER_NEGATIVE:
+ case INTEGER_ZERO_OR_POSITIVE:
+ if ( fhirValue instanceof IPrimitiveType && ( (IPrimitiveType) fhirValue ).getValue() instanceof Integer )
+ {
+ return ( (IPrimitiveType) fhirValue ).getValueAsString();
+ }
+
+ if ( fhirValue instanceof CodeableConcept )
+ {
+ return getCode( (CodeableConcept) fhirValue );
+ }
+
+ break;
+ case NUMBER:
+ case PERCENTAGE:
+ case UNIT_INTERVAL:
+ if ( fhirValue instanceof IPrimitiveType && ( (IPrimitiveType) fhirValue ).getValue() instanceof Number )
+ {
+ return ( (IPrimitiveType) fhirValue ).getValueAsString();
+ }
+
+ break;
+ case DATETIME:
+ case DATE:
+ case AGE:
+ if ( fhirValue instanceof DateTimeType )
+ {
+ return DateTimeFormatter.ISO_LOCAL_DATE_TIME
+ .format( ( (DateTimeType) fhirValue ).getValue().toInstant().atZone( ZoneId.systemDefault() ).toLocalDateTime() );
+ }
+
+ break;
+ case TIME:
+ if ( fhirValue instanceof TimeType )
+ {
+ return ( (TimeType) fhirValue ).getValueAsString();
+ }
+
+ break;
+ case BOOLEAN:
+ case TRUE_ONLY:
+ if ( fhirValue instanceof IPrimitiveType && ( (IPrimitiveType) fhirValue ).getValue() instanceof Boolean )
+ {
+ return ( (IPrimitiveType) fhirValue ).getValueAsString();
+ }
+
+ break;
+ default:
+ throw new TransformerDataException( "Unsupported DHIS2 value type: " + valueType );
+ }
+
+ throw new TransformerDataException( "Unsupported FHIR type " + fhirValue.getClass().getSimpleName() + " for DHIS2 value type " + valueType );
+ }
+
+ @Nullable
+ protected String getCode( @Nonnull CodeableConcept codeableConcept )
+ {
+ return codeableConcept.getCoding().stream().filter( c -> c.getSystem() == null ).map( Coding::getCode )
+ .findFirst().orElseThrow( () -> new TransformerDataException( "Codeable concept does not include a code (system must not be set)." ) );
+ }
+}
diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ValueTypeDhisToFhirTransformerUtils.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ValueTypeDhisToFhirTransformerUtils.java
new file mode 100644
index 00000000..586fc8e7
--- /dev/null
+++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ValueTypeDhisToFhirTransformerUtils.java
@@ -0,0 +1,135 @@
+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.parser.DataFormatException;
+import org.dhis2.fhir.adapter.dhis.converter.ValueConverter;
+import org.dhis2.fhir.adapter.dhis.model.Option;
+import org.dhis2.fhir.adapter.dhis.model.OptionSet;
+import org.dhis2.fhir.adapter.dhis.model.WritableOption;
+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.dhis.impl.util.AbstractValueTypeDhisToFhirTransformerUtils;
+import org.dhis2.fhir.adapter.model.ValueType;
+import org.dhis2.fhir.adapter.scriptable.Scriptable;
+import org.hl7.fhir.instance.model.api.IBaseDatatype;
+import org.hl7.fhir.r4.model.BooleanType;
+import org.hl7.fhir.r4.model.CodeableConcept;
+import org.hl7.fhir.r4.model.Coding;
+import org.hl7.fhir.r4.model.DateTimeType;
+import org.hl7.fhir.r4.model.DecimalType;
+import org.hl7.fhir.r4.model.IntegerType;
+import org.hl7.fhir.r4.model.StringType;
+import org.hl7.fhir.r4.model.TimeType;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Set;
+
+/**
+ * R4 specific implementation of {@link AbstractValueTypeDhisToFhirTransformerUtils}.
+ *
+ * @author volsch
+ */
+@Scriptable
+@Component
+public class R4ValueTypeDhisToFhirTransformerUtils extends AbstractValueTypeDhisToFhirTransformerUtils
+{
+ public R4ValueTypeDhisToFhirTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, @Nonnull ValueConverter valueConverter )
+ {
+ super( scriptExecutionContext, valueConverter );
+ }
+
+ @Nonnull
+ @Override
+ public Set getFhirVersions()
+ {
+ return FhirVersion.R4_ONLY;
+ }
+
+ @Nullable
+ @Override
+ protected IBaseDatatype convert( @Nullable String dhisValue, @Nonnull ValueType valueType, @Nullable OptionSet optionSet )
+ {
+ if ( dhisValue == null )
+ {
+ return null;
+ }
+
+ if ( optionSet != null )
+ {
+ final Option option = optionSet.getOptionalOptionByCode( dhisValue ).orElseGet( () -> new WritableOption( dhisValue, dhisValue ) );
+
+ return new CodeableConcept().addCoding( new Coding().setCode( option.getCode() ).setDisplay( option.getName() ) );
+ }
+
+ try
+ {
+ switch ( valueType )
+ {
+ case TEXT:
+ case LONG_TEXT:
+ case EMAIL:
+ case LETTER:
+ case ORGANISATION_UNIT:
+ case PHONE_NUMBER:
+ case TRACKER_ASSOCIATE:
+ case URL:
+ case USERNAME:
+ return new StringType( dhisValue );
+ case INTEGER:
+ case INTEGER_POSITIVE:
+ case INTEGER_NEGATIVE:
+ case INTEGER_ZERO_OR_POSITIVE:
+ return new IntegerType( dhisValue );
+ case NUMBER:
+ case PERCENTAGE:
+ case UNIT_INTERVAL:
+ return new DecimalType( dhisValue );
+ case DATETIME:
+ case DATE:
+ case AGE:
+ return new DateTimeType( dhisValue );
+ case TIME:
+ return new TimeType( dhisValue );
+ case BOOLEAN:
+ case TRUE_ONLY:
+ return new BooleanType( dhisValue );
+ default:
+ throw new TransformerDataException( "Unsupported DHIS2 value type: " + valueType );
+ }
+ }
+ catch ( DataFormatException | IllegalArgumentException e )
+ {
+ throw new TransformerDataException( "Value with value type " + valueType + " could not be parsed for setting corresponding FHIR value: " + dhisValue, e );
+ }
+ }
+}
diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4ValueTypeDhisToFhirTransformerUtilsTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4ValueTypeDhisToFhirTransformerUtilsTest.java
new file mode 100644
index 00000000..ab4bee0a
--- /dev/null
+++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/r4/R4ValueTypeDhisToFhirTransformerUtilsTest.java
@@ -0,0 +1,186 @@
+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.dhis.model.WritableOption;
+import org.dhis2.fhir.adapter.dhis.model.WritableOptionSet;
+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.fhir.impl.util.r4.R4ValueTypeDhisToFhirTransformerUtils;
+import org.hl7.fhir.r4.model.Base;
+import org.hl7.fhir.r4.model.BooleanType;
+import org.hl7.fhir.r4.model.CodeableConcept;
+import org.hl7.fhir.r4.model.Coding;
+import org.hl7.fhir.r4.model.DateTimeType;
+import org.hl7.fhir.r4.model.DecimalType;
+import org.hl7.fhir.r4.model.IntegerType;
+import org.hl7.fhir.r4.model.StringType;
+import org.hl7.fhir.r4.model.TimeType;
+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.Mockito;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.Collections;
+import java.util.Date;
+
+/**
+ * Unit tests for {@link R4ValueTypeDhisToFhirTransformerUtils}.
+ *
+ * @author volsch
+ */
+public class R4ValueTypeDhisToFhirTransformerUtilsTest
+{
+ @Mock
+ private ScriptExecutionContext scriptExecutionContext;
+
+ @Mock
+ private ValueConverter valueConverter;
+
+ @InjectMocks
+ private R4ValueTypeDhisToFhirTransformerUtils utils;
+
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule().silent();
+
+ @Before
+ public void setUp()
+ {
+ Mockito.when( valueConverter.convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) ) )
+ .thenAnswer( invocation -> invocation.getArgument( 0 ) );
+ }
+
+ @Test
+ public void getFhirVersions()
+ {
+ Assert.assertEquals( FhirVersion.R4_ONLY, utils.getFhirVersions() );
+ }
+
+ @Test
+ public void convertNull()
+ {
+ Assert.assertNull( utils.convert( null, "text", null ) );
+ }
+
+ @Test
+ public void convertText()
+ {
+ Assert.assertTrue( new StringType( "This is a test" ).equalsDeep( (Base) utils.convert( "This is a test", "text", null ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertUnsupportedType()
+ {
+ utils.convert( "This is a test", "image", null );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test
+ public void convertInteger()
+ {
+ Assert.assertTrue( new IntegerType( 29837 ).equalsDeep( (Base) utils.convert( "29837", "Integer", null ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertIntegerDataFormat()
+ {
+ utils.convert( "298x37", "Integer", null );
+ }
+
+ @Test
+ public void convertNumber()
+ {
+ Assert.assertTrue( new DecimalType( 29837.5 ).equalsDeep( (Base) utils.convert( "29837.5", "Number", null ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test
+ public void convertBoolean()
+ {
+ Assert.assertTrue( new BooleanType( true ).equalsDeep( (Base) utils.convert( "true", "BOOLEAN", null ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test
+ public void convertTime()
+ {
+ Assert.assertTrue( new TimeType( "17:48:12" ).equalsDeep( (Base) utils.convert( "17:48:12", "Time", null ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test
+ public void convertDateTime()
+ {
+ Assert.assertTrue( new DateTimeType( Date.from( ZonedDateTime.of( 2018, 7, 21, 17, 48, 12, 0, ZoneId.systemDefault() ).toInstant() ) )
+ .equalsDeep( (Base) utils.convert( "2018-07-21T17:48:12", "datetime", null ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test
+ public void convertOption()
+ {
+ final WritableOptionSet optionSet = new WritableOptionSet();
+ optionSet.setOptions( Collections.singletonList( new WritableOption( "test1", "Test 1" ) ) );
+
+ Assert.assertTrue( new CodeableConcept().addCoding( new Coding().setCode( "test1" ).setDisplay( "Test 1" ) )
+ .equalsDeep( (Base) utils.convert( "test1", "text", optionSet ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+
+ @Test
+ public void convertOptionNotFound()
+ {
+ final WritableOptionSet optionSet = new WritableOptionSet();
+ optionSet.setOptions( Collections.singletonList( new WritableOption( "test1", "Test 1" ) ) );
+
+ Assert.assertTrue( new CodeableConcept().addCoding( new Coding().setCode( "test2" ).setDisplay( "test2" ) )
+ .equalsDeep( (Base) utils.convert( "test2", "text", optionSet ) ) );
+
+ Mockito.verify( valueConverter ).convert( Mockito.any(), Mockito.any(), Mockito.eq( String.class ) );
+ }
+}
\ No newline at end of file
diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ValueTypeFhirToDhisTransformerUtilsTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ValueTypeFhirToDhisTransformerUtilsTest.java
new file mode 100644
index 00000000..a3048784
--- /dev/null
+++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/r4/R4ValueTypeFhirToDhisTransformerUtilsTest.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.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.dhis.impl.util.r4.R4ValueTypeFhirToDhisTransformerUtils;
+import org.dhis2.fhir.adapter.model.ValueType;
+import org.hl7.fhir.r4.model.BooleanType;
+import org.hl7.fhir.r4.model.CodeableConcept;
+import org.hl7.fhir.r4.model.Coding;
+import org.hl7.fhir.r4.model.DateTimeType;
+import org.hl7.fhir.r4.model.DecimalType;
+import org.hl7.fhir.r4.model.IntegerType;
+import org.hl7.fhir.r4.model.StringType;
+import org.hl7.fhir.r4.model.TimeType;
+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.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+
+/**
+ * Unit tests for {@link R4ValueTypeFhirToDhisTransformerUtils}.
+ *
+ * @author volsch
+ */
+public class R4ValueTypeFhirToDhisTransformerUtilsTest
+{
+ @Mock
+ private ScriptExecutionContext scriptExecutionContext;
+
+ @InjectMocks
+ private R4ValueTypeFhirToDhisTransformerUtils utils;
+
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ @Test
+ public void getFhirVersions()
+ {
+ Assert.assertEquals( FhirVersion.R4_ONLY, utils.getFhirVersions() );
+ }
+
+ @Test
+ public void convertNull()
+ {
+ Assert.assertNull( utils.convert( null, ValueType.TEXT ) );
+ }
+
+ @Test
+ public void convertText()
+ {
+ Assert.assertEquals( "Das ist ein Test!", utils.convert( new StringType( "Das ist ein Test!" ), "text" ) );
+ }
+
+ @Test
+ public void convertTextCode()
+ {
+ Assert.assertEquals( "test1", utils.convert( new CodeableConcept().addCoding( new Coding().setCode( "test1" ) ), "Text" ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertTextCodeWithSystem()
+ {
+ utils.convert( new CodeableConcept().addCoding( new Coding().setSystem( "abc" ).setCode( "test1" ) ), "text" );
+ }
+
+ @Test
+ public void convertInteger()
+ {
+ Assert.assertEquals( "736384", utils.convert( new IntegerType( 736384 ), "integer" ) );
+ }
+
+ @Test
+ public void convertIntegerCode()
+ {
+ Assert.assertEquals( "736384", utils.convert( new CodeableConcept().addCoding( new Coding().setCode( "736384" ) ), "integer" ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertIntegerInvalid()
+ {
+ utils.convert( new TimeType( "12:47:21" ), "integer" );
+ }
+
+ @Test
+ public void convertNumber()
+ {
+ Assert.assertEquals( "736384.5", utils.convert( new DecimalType( 736384.5 ), "number" ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertNumberInvalid()
+ {
+ utils.convert( new TimeType( "12:47:21" ), "Number" );
+ }
+
+ @Test
+ public void convertDateTime()
+ {
+ final LocalDateTime expected = ZonedDateTime.of( 2019, 7, 21, 16, 48, 12, 0, ZoneId.ofOffset( "UTC", ZoneOffset.ofHours( 7 ) ) )
+ .withZoneSameInstant( ZoneId.systemDefault() ).toLocalDateTime();
+
+ Assert.assertEquals( DateTimeFormatter.ISO_LOCAL_DATE_TIME.format( expected.atZone( ZoneId.systemDefault() ) ),
+ utils.convert( new DateTimeType( "2019-07-21T16:48:12+07:00" ), "datetime" ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertDateTimeInvalid()
+ {
+ utils.convert( new TimeType( "12:47:21" ), "datetime" );
+ }
+
+ @Test
+ public void convertTime()
+ {
+ Assert.assertEquals( "12:47:21", utils.convert( new TimeType( "12:47:21" ), "time" ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertTimeInvalid()
+ {
+ utils.convert( new DateTimeType( new Date() ), "time" );
+ }
+
+ @Test
+ public void convertBoolean()
+ {
+ Assert.assertEquals( "true", utils.convert( new BooleanType( true ), "boolean" ) );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertBooleanInvalid()
+ {
+ utils.convert( new DateTimeType( new Date() ), "boolean" );
+ }
+
+ @Test( expected = TransformerDataException.class )
+ public void convertUnsupportedValueType()
+ {
+ utils.convert( new DateTimeType( new Date() ), "image" );
+ }
+}
\ No newline at end of file
diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/AbstractValueTypeDhisToFhirTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/AbstractValueTypeDhisToFhirTransformerUtils.java
new file mode 100644
index 00000000..c96a808c
--- /dev/null
+++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/AbstractValueTypeDhisToFhirTransformerUtils.java
@@ -0,0 +1,129 @@
+package org.dhis2.fhir.adapter.fhir.transform.dhis.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 org.dhis2.fhir.adapter.dhis.converter.ValueConverter;
+import org.dhis2.fhir.adapter.dhis.model.OptionSet;
+import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext;
+import org.dhis2.fhir.adapter.fhir.transform.util.AbstractTransformerUtils;
+import org.dhis2.fhir.adapter.model.ValueType;
+import org.dhis2.fhir.adapter.scriptable.ScriptMethod;
+import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg;
+import org.dhis2.fhir.adapter.scriptable.ScriptTransformType;
+import org.dhis2.fhir.adapter.scriptable.ScriptType;
+import org.dhis2.fhir.adapter.scriptable.Scriptable;
+import org.dhis2.fhir.adapter.util.NameUtils;
+import org.hl7.fhir.instance.model.api.IBaseDatatype;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * Abstract base class for converting DHIS2 value typed values to FHIR types.
+ *
+ * @author volsch
+ */
+@Scriptable
+@ScriptType( value = "ValueTypeUtils", transformType = ScriptTransformType.EXP, var = AbstractValueTypeDhisToFhirTransformerUtils.SCRIPT_ATTR_NAME,
+ description = "Utilities for handling conversion of DHIS2 values with a DHIS2 value type." )
+public abstract class AbstractValueTypeDhisToFhirTransformerUtils extends AbstractTransformerUtils implements DhisToFhirTransformerUtils
+{
+ public static final String SCRIPT_ATTR_NAME = "valueTypeUtils";
+
+ private final ValueConverter valueConverter;
+
+ protected AbstractValueTypeDhisToFhirTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext, @Nonnull ValueConverter valueConverter )
+ {
+ super( scriptExecutionContext );
+
+ this.valueConverter = valueConverter;
+ }
+
+ @Nonnull
+ @Override
+ public String getScriptAttrName()
+ {
+ return SCRIPT_ATTR_NAME;
+ }
+
+ @ScriptMethod( description = "Returns if the specified DHIS2 value type is supported.",
+ args = @ScriptMethodArg( value = "valueType", description = "The DHIS2 value type that should be checked." ),
+ returnDescription = "A boolean value that indicates if the value is supported." )
+ public boolean isSupportedValueType( @Nonnull Object valueType )
+ {
+ final ValueType convertedValueType = NameUtils.toEnumValue( ValueType.class, valueType );
+
+ switch ( convertedValueType )
+ {
+ case TEXT:
+ case EMAIL:
+ case LETTER:
+ case ORGANISATION_UNIT:
+ case PHONE_NUMBER:
+ case TRACKER_ASSOCIATE:
+ case URL:
+ case USERNAME:
+ case LONG_TEXT:
+ case INTEGER:
+ case INTEGER_POSITIVE:
+ case INTEGER_NEGATIVE:
+ case INTEGER_ZERO_OR_POSITIVE:
+ case NUMBER:
+ case PERCENTAGE:
+ case UNIT_INTERVAL:
+ case DATETIME:
+ case AGE:
+ case DATE:
+ case TIME:
+ case BOOLEAN:
+ case TRUE_ONLY:
+ return true;
+ }
+
+ return false;
+ }
+
+ @ScriptMethod( description = "Returns the DHIS2 value as FHIR value. The value is converted according to the specified value type.",
+ args = {
+ @ScriptMethodArg( value = "dhisValue", description = "The DHIS2 typed value." ),
+ @ScriptMethodArg( value = "valueType", description = "The DHIS2 value from which the FHIR value should be converted." ),
+ @ScriptMethodArg( value = "optionSet", description = "The DHIS2 option when the code belongs to a DHIS2 option set." )
+ },
+ returnDescription = "The DHIS2 value as FHIR value converted to a FHIR datatype." )
+ @Nullable
+ public IBaseDatatype convert( @Nullable Object dhisValue, @Nonnull Object valueType, @Nullable OptionSet optionSet )
+ {
+ final ValueType convertedValueType = NameUtils.toEnumValue( ValueType.class, valueType );
+
+ return convert( valueConverter.convert( dhisValue, convertedValueType, String.class ), convertedValueType, optionSet );
+ }
+
+ @Nullable
+ protected abstract IBaseDatatype convert( @Nullable String dhisValue, @Nonnull ValueType valueType, @Nullable OptionSet optionSet );
+}
diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/AbstractValueTypeFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/AbstractValueTypeFhirToDhisTransformerUtils.java
new file mode 100644
index 00000000..364d3a57
--- /dev/null
+++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/util/AbstractValueTypeFhirToDhisTransformerUtils.java
@@ -0,0 +1,86 @@
+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 org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext;
+import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.util.DhisToFhirTransformerUtils;
+import org.dhis2.fhir.adapter.fhir.transform.util.AbstractTransformerUtils;
+import org.dhis2.fhir.adapter.model.ValueType;
+import org.dhis2.fhir.adapter.scriptable.ScriptMethod;
+import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg;
+import org.dhis2.fhir.adapter.scriptable.ScriptTransformType;
+import org.dhis2.fhir.adapter.scriptable.ScriptType;
+import org.dhis2.fhir.adapter.scriptable.Scriptable;
+import org.dhis2.fhir.adapter.util.NameUtils;
+import org.hl7.fhir.instance.model.api.IBaseDatatype;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * Abstract base class for converting FHIR types to DHIS2 value typed values.
+ *
+ * @author volsch
+ */
+@Scriptable
+@ScriptType( value = "ValueTypeUtils", transformType = ScriptTransformType.IMP, var = AbstractValueTypeFhirToDhisTransformerUtils.SCRIPT_ATTR_NAME,
+ description = "Utilities for handling conversion of DHIS2 values with a DHIS2 value type." )
+public abstract class AbstractValueTypeFhirToDhisTransformerUtils extends AbstractTransformerUtils implements DhisToFhirTransformerUtils
+{
+ public static final String SCRIPT_ATTR_NAME = "valueTypeUtils";
+
+ protected AbstractValueTypeFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext )
+ {
+ super( scriptExecutionContext );
+ }
+
+ @Nonnull
+ @Override
+ public String getScriptAttrName()
+ {
+ return SCRIPT_ATTR_NAME;
+ }
+
+ @ScriptMethod( description = "Returns the FHIR value as DHIS2 value. The value is converted according to the specified value type.",
+ args = {
+ @ScriptMethodArg( value = "fhirValue", description = "The FHIR typed value." ),
+ @ScriptMethodArg( value = "valueType", description = "The DHIS2 value type to which the FHIR value should be converted." )
+ },
+ returnDescription = "The FHIR value as DHIS2 value converted to the DHIS2 value type." )
+ @Nullable
+ public Object convert( @Nullable IBaseDatatype fhirValue, @Nonnull Object valueType )
+ {
+ final ValueType convertedValueType = NameUtils.toEnumValue( ValueType.class, valueType );
+
+ return convert( fhirValue, convertedValueType );
+ }
+
+ @Nullable
+ protected abstract Object convert( @Nullable IBaseDatatype fhirValue, @Nonnull ValueType valueType );
+}
diff --git a/fhir/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/AbstractValueTypeDhisToFhirTransformerUtilsTest.java b/fhir/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/AbstractValueTypeDhisToFhirTransformerUtilsTest.java
new file mode 100644
index 00000000..129c6a89
--- /dev/null
+++ b/fhir/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/util/AbstractValueTypeDhisToFhirTransformerUtilsTest.java
@@ -0,0 +1,78 @@
+package org.dhis2.fhir.adapter.fhir.transform.dhis.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 org.dhis2.fhir.adapter.dhis.converter.ValueConverter;
+import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext;
+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;
+
+/**
+ * Unit tests for {@link AbstractValueTypeDhisToFhirTransformerUtils}.
+ *
+ * @author volsch
+ */
+public class AbstractValueTypeDhisToFhirTransformerUtilsTest
+{
+ @Mock
+ private ScriptExecutionContext scriptExecutionContext;
+
+ @Mock
+ private ValueConverter valueConverter;
+
+ private AbstractValueTypeDhisToFhirTransformerUtils utils;
+
+ @Rule
+ public MockitoRule mockitoRule = MockitoJUnit.rule();
+
+ @Before
+ public void setUp()
+ {
+ utils = Mockito.mock( AbstractValueTypeDhisToFhirTransformerUtils.class, Mockito.withSettings()
+ .useConstructor( scriptExecutionContext, valueConverter ).defaultAnswer( Mockito.CALLS_REAL_METHODS ) );
+ }
+
+ @Test
+ public void isSupportedValueType()
+ {
+ Assert.assertTrue( utils.isSupportedValueType( "integer" ) );
+ }
+
+ @Test
+ public void isSupportedValueTypeNot()
+ {
+ Assert.assertFalse( utils.isSupportedValueType( "Image" ) );
+ }
+}
\ No newline at end of file