diff --git a/README.md b/README.md index a862822d..d755a433 100644 --- a/README.md +++ b/README.md @@ -126,4 +126,7 @@ With the default configuration the initial setup user interface can be accessed ### API for Administration and Mapping The adapter provides REST interfaces for administration and mapping. The documentation is currently generated automatically when building the adapter. Unit test execution must not be skipped in this case when building the adapter. The documentation can be found at docs/api-guide.html. If the Adapter has been started by command line without changing the port, then the guide is available at http://localhost:8081/docs/api-guide.html. + +The JavaScript API that is used to create rules and transformations is generated automatically when running the adapter. The script can be + found at scripts/to-dhis2-all-mapping.js. If the Adapter has been started by command line without changing the port, then the guide is available at http://localhost:8081/scripts/to-dhis2-all-mapping.js. \ No newline at end of file diff --git a/app/src/main/java/org/dhis2/fhir/adapter/WebSecurityConfig.java b/app/src/main/java/org/dhis2/fhir/adapter/WebSecurityConfig.java index c291547e..d216a951 100644 --- a/app/src/main/java/org/dhis2/fhir/adapter/WebSecurityConfig.java +++ b/app/src/main/java/org/dhis2/fhir/adapter/WebSecurityConfig.java @@ -83,6 +83,7 @@ protected void configure( @Nonnull HttpSecurity http ) throws Exception .antMatchers( HttpMethod.GET, "/actuator/info" ).permitAll() .antMatchers( HttpMethod.GET, "/docs/**" ).permitAll() .antMatchers( HttpMethod.GET, "/dhis/metadata/**" ).permitAll() + .antMatchers( HttpMethod.GET, "/script/**" ).permitAll() .antMatchers( HttpMethod.OPTIONS, "/api/**" ).permitAll() .antMatchers( "/actuator/**" ).hasRole( AdapterAuthorities.ADMINISTRATION_AUTHORITY ) .anyRequest().authenticated() diff --git a/app/src/main/java/org/dhis2/fhir/adapter/setup/ReferenceSetup.java b/app/src/main/java/org/dhis2/fhir/adapter/setup/ReferenceSetup.java index b9381085..9b53bd4d 100644 --- a/app/src/main/java/org/dhis2/fhir/adapter/setup/ReferenceSetup.java +++ b/app/src/main/java/org/dhis2/fhir/adapter/setup/ReferenceSetup.java @@ -28,6 +28,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import org.apache.commons.lang3.StringUtils; import org.dhis2.fhir.adapter.dhis.model.Reference; import org.dhis2.fhir.adapter.dhis.model.ReferenceType; @@ -101,7 +102,7 @@ public void setReferenceValue( String referenceValue ) @Nonnull public Reference getReference() { - return new Reference( getReferenceValue(), getReferenceType() ); + return new Reference( StringUtils.trimToNull( getReferenceValue() ), getReferenceType() ); } @Nonnull diff --git a/common/pom.xml b/common/pom.xml index 39414203..20f2d15d 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -54,5 +54,10 @@ org.springframework.boot spring-boot-starter-data-redis + + + org.apache.commons + commons-text + diff --git a/common/src/main/java/org/dhis2/fhir/adapter/geo/GeoBasePackage.java b/common/src/main/java/org/dhis2/fhir/adapter/geo/GeoBasePackage.java new file mode 100644 index 00000000..baf223d9 --- /dev/null +++ b/common/src/main/java/org/dhis2/fhir/adapter/geo/GeoBasePackage.java @@ -0,0 +1,38 @@ +package org.dhis2.fhir.adapter.geo; + +/* + * Copyright (c) 2004-2018, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Marker interface that is used to reference package as base package. + * + * @author volsch + */ +public interface GeoBasePackage +{ +} diff --git a/common/src/main/java/org/dhis2/fhir/adapter/geo/Geometry.java b/common/src/main/java/org/dhis2/fhir/adapter/geo/Geometry.java index 95600182..837b4c7f 100644 --- a/common/src/main/java/org/dhis2/fhir/adapter/geo/Geometry.java +++ b/common/src/main/java/org/dhis2/fhir/adapter/geo/Geometry.java @@ -28,7 +28,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; +import org.dhis2.fhir.adapter.scriptable.Scriptable; /** * Base interface for geometry objects. diff --git a/common/src/main/java/org/dhis2/fhir/adapter/geo/Location.java b/common/src/main/java/org/dhis2/fhir/adapter/geo/Location.java index 984252fd..484cf39f 100644 --- a/common/src/main/java/org/dhis2/fhir/adapter/geo/Location.java +++ b/common/src/main/java/org/dhis2/fhir/adapter/geo/Location.java @@ -28,7 +28,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import java.io.Serializable; import java.util.Objects; @@ -39,6 +41,7 @@ * @author volsch */ @Scriptable +@ScriptType( value = "Location", description = "Point geometry with a longitude and latitude." ) public class Location implements Geometry, Serializable { private static final long serialVersionUID = 7916805545140123930L; @@ -58,17 +61,20 @@ public Location( double longitude, double latitude ) this.latitude = latitude; } + @ScriptMethod( description = "Returns the longitude of the point geometry." ) public double getLongitude() { return longitude; } + @ScriptMethod( description = "Returns the latitude of the point geometry." ) public double getLatitude() { return latitude; } @Override + @ScriptMethod public boolean equals( Object o ) { if ( this == o ) return true; diff --git a/common/src/main/java/org/dhis2/fhir/adapter/scriptable/ScriptMethod.java b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/ScriptMethod.java new file mode 100644 index 00000000..b67ef850 --- /dev/null +++ b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/ScriptMethod.java @@ -0,0 +1,63 @@ +package org.dhis2.fhir.adapter.scriptable; + +/* + * Copyright (c) 2004-2018, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Methods that are annotated by this annotation are either included in + * script type as properties with optional getters and setters or as functions + * (depending on their signature. + * + * @author volsch + */ +@Target( { ElementType.METHOD } ) +@Retention( RetentionPolicy.RUNTIME ) +@Documented +public @interface ScriptMethod +{ + /** + * @return the description of the script method. + */ + String description() default ""; + + /** + * @return the definition of the script method arguments. + */ + ScriptMethodArg[] args() default {}; + + /** + * @return the description of the return value (if any). + */ + String returnDescription() default ""; +} diff --git a/common/src/main/java/org/dhis2/fhir/adapter/scriptable/ScriptMethodArg.java b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/ScriptMethodArg.java new file mode 100644 index 00000000..99940f3f --- /dev/null +++ b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/ScriptMethodArg.java @@ -0,0 +1,57 @@ +package org.dhis2.fhir.adapter.scriptable; + +/* + * Copyright (c) 2004-2018, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Method arguments that are annotated by this annotation are documented in the + * script with the specified documentation. + * + * @author volsch + */ +@Target( { ElementType.PARAMETER } ) +@Retention( RetentionPolicy.RUNTIME ) +@Documented +public @interface ScriptMethodArg +{ + /** + * @return the name of the script method argument. + */ + String value(); + + /** + * @return the description of the script method argument. + */ + String description() default ""; +} diff --git a/common/src/main/java/org/dhis2/fhir/adapter/scriptable/ScriptType.java b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/ScriptType.java new file mode 100644 index 00000000..c2d64085 --- /dev/null +++ b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/ScriptType.java @@ -0,0 +1,71 @@ +package org.dhis2.fhir.adapter.scriptable; + +/* + * Copyright (c) 2004-2018, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Classes or interfaces that are annotated by this annotation will be includes + * as a class in a scripting language. An instance of this class will be available + * as variable. + * + * @author volsch + */ +@Target( { ElementType.TYPE } ) +@Retention( RetentionPolicy.RUNTIME ) +@Documented +@Inherited +public @interface ScriptType +{ + /** + * @return the name of the type (can be instantiated with new in script). + */ + String value(); + + /** + * @return the name of the variable to which the instance of this type is assigned. + */ + String var() default ""; + + /** + * @return the description of the script type. + */ + String description() default ""; + + /** + * @return the name of the transformation data type that is associated with this type + * or an empty string if no transformation data type is associated with this type. + */ + String transformDataType() default ""; +} diff --git a/common/src/main/java/org/dhis2/fhir/adapter/Scriptable.java b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/Scriptable.java similarity index 97% rename from common/src/main/java/org/dhis2/fhir/adapter/Scriptable.java rename to common/src/main/java/org/dhis2/fhir/adapter/scriptable/Scriptable.java index c6330498..38d1160f 100644 --- a/common/src/main/java/org/dhis2/fhir/adapter/Scriptable.java +++ b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/Scriptable.java @@ -1,4 +1,4 @@ -package org.dhis2.fhir.adapter; +package org.dhis2.fhir.adapter.scriptable; /* * Copyright (c) 2004-2018, University of Oslo diff --git a/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/JavaScriptGeneratorConfig.java b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/JavaScriptGeneratorConfig.java new file mode 100644 index 00000000..125b6cc0 --- /dev/null +++ b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/JavaScriptGeneratorConfig.java @@ -0,0 +1,51 @@ +package org.dhis2.fhir.adapter.scriptable.generator; + +/* + * Copyright (c) 2004-2018, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * The configuration of the JavaScript generator. If this configuration is + * present as bean the controller will also be available. + * + * @author volsch + */ +public class JavaScriptGeneratorConfig +{ + private Class[] basePackageClasses; + + public Class[] getBasePackageClasses() + { + return basePackageClasses; + } + + public JavaScriptGeneratorConfig setBasePackageClasses( Class... basePackageClasses ) + { + this.basePackageClasses = basePackageClasses; + return this; + } +} diff --git a/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/JavaScriptGeneratorConfigException.java b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/JavaScriptGeneratorConfigException.java new file mode 100644 index 00000000..6407d7ce --- /dev/null +++ b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/JavaScriptGeneratorConfigException.java @@ -0,0 +1,49 @@ +package org.dhis2.fhir.adapter.scriptable.generator; + +/* + * Copyright (c) 2004-2018, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Thrown if there is any configuration error with the JavaScript generator. + * + * @author volsch + */ +public class JavaScriptGeneratorConfigException extends RuntimeException +{ + private static final long serialVersionUID = 5501361896506304730L; + + public JavaScriptGeneratorConfigException( String message ) + { + super( message ); + } + + public JavaScriptGeneratorConfigException( String message, Throwable cause ) + { + super( message, cause ); + } +} diff --git a/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/JavaScriptGeneratorController.java b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/JavaScriptGeneratorController.java new file mode 100644 index 00000000..74e2a147 --- /dev/null +++ b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/JavaScriptGeneratorController.java @@ -0,0 +1,368 @@ +package org.dhis2.fhir.adapter.scriptable.generator; + +/* + * Copyright (c) 2004-2018, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.reflect.MethodUtils; +import org.apache.commons.text.WordUtils; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.context.request.WebRequest; + +import javax.annotation.Nonnull; +import javax.annotation.PostConstruct; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.LineNumberReader; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.stream.Collectors; + +/** + * The controller that provides the downloadable script. + * + * @author volsch + */ +@ConditionalOnBean( JavaScriptGeneratorConfig.class ) +@Controller +public class JavaScriptGeneratorController +{ + public static final String LICENSE_FILE = "classpath:/dhis2-license.txt"; + + public static final String LINE_ENDING = "\r\n"; + + public static final int MAX_COMMENT_LENGTH = 80; + + private final JavaScriptGeneratorConfig config; + + private final ResourceLoader resourceLoader; + + private String script; + + private Instant lastModified; + + private String eTag; + + public JavaScriptGeneratorController( @SuppressWarnings( "SpringJavaInjectionPointsAutowiringInspection" ) @Nonnull JavaScriptGeneratorConfig config, @Nonnull ResourceLoader resourceLoader ) + { + this.config = config; + this.resourceLoader = resourceLoader; + } + + @RequestMapping( path = "/scripts/to-dhis2-all-mapping.js", method = RequestMethod.GET, produces = "application/javascript;charset=UTF-8" ) + public ResponseEntity getScript( @Nonnull WebRequest request ) + { + if ( request.checkNotModified( eTag, lastModified.toEpochMilli() ) ) + { + return null; + } + + final HttpHeaders headers = new HttpHeaders(); + headers.setLastModified( lastModified.toEpochMilli() ); + headers.setETag( eTag ); + return new ResponseEntity<>( script, headers, HttpStatus.OK ); + } + + @PostConstruct + protected void init() + { + lastModified = Instant.now(); + + final SortedMap> orderedClasses = new TreeMap<>(); + final Set processedAnnotations = new HashSet<>(); + final List scriptTypeInfoList = new ArrayList<>(); + findAllScriptTypes().forEach( c -> { + final ScriptType scriptType = AnnotationUtils.findAnnotation( c, ScriptType.class ); + if ( (scriptType != null) && processedAnnotations.add( scriptType ) ) + { + if ( orderedClasses.put( scriptType.value(), c ) != null ) + { + throw new JavaScriptGeneratorConfigException( "Duplicate script type: " + c ); + } + scriptTypeInfoList.add( new ScriptTypeInfo( c, scriptType ) ); + } + } ); + + final StringBuilder sb = new StringBuilder( createCommentedLicense() ); + scriptTypeInfoList.forEach( scriptTypeInfo -> { + final TypeInfo typeInfo = createTypeInfo( scriptTypeInfo.getAnnotatedClass() ); + final ScriptType st = scriptTypeInfo.getScriptType(); + + sb.append( "/**" ).append( LINE_ENDING ); + Arrays.stream( st.description().split( "\n" ) ) + .forEach( l -> sb.append( " * " ).append( WordUtils.wrap( l, MAX_COMMENT_LENGTH, LINE_ENDING + " * ", false ) ) ); + sb.append( LINE_ENDING ).append( " */" ).append( LINE_ENDING ); + sb.append( "var " ).append( st.value() ).append( " = (function ()" ).append( LINE_ENDING ).append( "{" ).append( LINE_ENDING ); + sb.append( " function " ).append( st.value() ).append( "()" ).append( LINE_ENDING ).append( " {" ).append( LINE_ENDING ); + typeInfo.getPropertyInfo().forEach( pi -> { + if ( StringUtils.isNotBlank( pi.getScriptMethod().description() ) ) + { + sb.append( " /**" ).append( LINE_ENDING ); + Arrays.stream( pi.getScriptMethod().description().split( "\n" ) ) + .forEach( l -> sb.append( " * " ).append( WordUtils.wrap( l, MAX_COMMENT_LENGTH, LINE_ENDING + " * ", false ) ) ); + sb.append( LINE_ENDING ).append( " */" ).append( LINE_ENDING ); + } + sb.append( " this." ).append( pi.getName() ).append( " = null;" ).append( LINE_ENDING ).append( LINE_ENDING ); + } ); + sb.append( " }" ).append( LINE_ENDING ).append( LINE_ENDING ); + + typeInfo.getMethodInfo().forEach( mi -> { + sb.append( " /**" ).append( LINE_ENDING ); + if ( StringUtils.isNotBlank( mi.getScriptMethod().description() ) ) + { + Arrays.stream( mi.getScriptMethod().description().split( "\n" ) ) + .forEach( l -> sb.append( " * " ).append( WordUtils.wrap( l, MAX_COMMENT_LENGTH, LINE_ENDING + " * ", false ) ) ); + sb.append( LINE_ENDING ); + if ( !mi.getArgs().isEmpty() || !mi.isVoidMethod() ) + { + sb.append( " * " ).append( LINE_ENDING ); + } + } + if ( !mi.getArgs().isEmpty() ) + { + final int max = mi.getArgs().stream().map( a -> a.getName().length() ).max( Comparator.naturalOrder() ).orElse( 0 ); + final int tab = max + 4; + mi.getArgs().forEach( a -> { + String description = ""; + if ( (a.getScriptMethodArg() != null) && StringUtils.isNotBlank( a.getScriptMethodArg().description() ) ) + { + description = a.getScriptMethodArg().description(); + } + else if ( mi.isProperty() ) + { + description = mi.getScriptMethod().description(); + } + sb.append( " * @param " ).append( a.getName() ).append( StringUtils.repeat( ' ', max - a.getName().length() ) ).append( ' ' ); + Arrays.stream( description.split( "\n" ) ).filter( StringUtils::isNotBlank ) + .forEach( l -> sb.append( WordUtils.wrap( l, MAX_COMMENT_LENGTH - tab, LINE_ENDING + " * " + StringUtils.repeat( ' ', tab ), false ) ) ); + sb.append( LINE_ENDING ); + } ); + } + if ( !mi.isVoidMethod() ) + { + String returnDescription = ""; + if ( StringUtils.isNotBlank( mi.getScriptMethod().returnDescription() ) ) + { + returnDescription = mi.getScriptMethod().returnDescription(); + } + else if ( mi.isProperty() ) + { + returnDescription = mi.getScriptMethod().description(); + } + sb.append( " * @return " ); + Arrays.stream( returnDescription.split( "\n" ) ).filter( StringUtils::isNotBlank ) + .forEach( l -> sb.append( WordUtils.wrap( l, MAX_COMMENT_LENGTH - 8, LINE_ENDING + " * ", false ) ) ); + sb.append( LINE_ENDING ); + } + sb.append( " */" ).append( LINE_ENDING ); + sb.append( " " ).append( st.value() ).append( ".prototype." ).append( mi.getName() ).append( " = function (" ); + boolean first = true; + for ( final MethodArgInfo a : mi.getArgs() ) + { + if ( first ) + { + first = false; + } + else + { + sb.append( ", " ); + } + sb.append( a.getName() ); + } + sb.append( ") {};" ).append( LINE_ENDING ).append( LINE_ENDING ); + } ); + + sb.append( " return " ).append( st.value() ).append( ";" ).append( LINE_ENDING ); + sb.append( "}());" ).append( LINE_ENDING ); + if ( StringUtils.isNotBlank( st.var() ) ) + { + sb.append( "var " ).append( st.var() ).append( " = new " ).append( st.value() ).append( "();" ).append( LINE_ENDING ); + } + sb.append( LINE_ENDING ); + } ); + + script = sb.toString(); + eTag = "\"" + createSha1( script ) + "\""; + } + + @Nonnull + private String createCommentedLicense() + { + final StringBuilder sb = new StringBuilder( "/*" ).append( LINE_ENDING ); + try ( final LineNumberReader r = new LineNumberReader( new InputStreamReader( resourceLoader.getResource( LICENSE_FILE ).getInputStream(), StandardCharsets.UTF_8 ) ) ) + { + String line; + while ( (line = r.readLine()) != null ) + { + sb.append( " * " ).append( line ).append( LINE_ENDING ); + } + } + catch ( IOException e ) + { + throw new JavaScriptGeneratorConfigException( "Could not load license file " + LICENSE_FILE ); + } + return sb.append( " */" ).append( LINE_ENDING ).append( LINE_ENDING ).toString(); + } + + @Nonnull + private Set> findAllScriptTypes() + { + final ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider( false ); + componentProvider.setResourceLoader( resourceLoader ); + componentProvider.addIncludeFilter( new AnnotationTypeFilter( ScriptType.class, false, true ) ); + + final Set> scriptTypeClasses = new HashSet<>(); + Arrays.stream( config.getBasePackageClasses() ).map( c -> c.getPackage().getName() ).forEach( packageName -> componentProvider.findCandidateComponents( packageName ).forEach( c -> { + try + { + scriptTypeClasses.add( Class.forName( c.getBeanClassName(), false, resourceLoader.getClassLoader() ) ); + } + catch ( ClassNotFoundException e ) + { + // can only happen if there is a big misconfiguration with the class loader + throw new JavaScriptGeneratorConfigException( "Could not load Spring scanned class " + c.getBeanClassName(), e ); + } + } ) ); + + return scriptTypeClasses; + } + + @Nonnull + private TypeInfo createTypeInfo( @Nonnull Class c ) + { + final Map properties = new HashMap<>(); + final Map methods = new HashMap<>(); + MethodUtils.getMethodsListWithAnnotation( c, ScriptMethod.class, true, false ).stream().distinct().forEach( m -> { + final ScriptMethod scriptMethod = m.getAnnotation( ScriptMethod.class ); + final String name = m.getName(); + boolean property = false; + if ( name.startsWith( "is" ) && (name.length() > 2) && (m.getParameterCount() == 0) && boolean.class.equals( m.getReturnType() ) ) + { + properties.computeIfAbsent( StringUtils.uncapitalize( name.substring( 2 ) ), k -> new PropertyInfo( k, scriptMethod ) ).setRead( scriptMethod ); + property = true; + } + else if ( name.startsWith( "get" ) && (name.length() > 3) && (m.getParameterCount() == 0) && !Void.class.equals( m.getReturnType() ) ) + { + properties.computeIfAbsent( StringUtils.uncapitalize( name.substring( 3 ) ), k -> new PropertyInfo( k, scriptMethod ) ).setRead( scriptMethod ); + property = true; + } + else if ( name.startsWith( "set" ) && (name.length() > 3) && (m.getParameterCount() == 1) ) + { + properties.computeIfAbsent( StringUtils.uncapitalize( name.substring( 3 ) ), k -> new PropertyInfo( k, scriptMethod ) ).setWrite( scriptMethod ); + property = true; + } + + final Map scriptMethodArgs = Arrays.stream( scriptMethod.args() ).collect( Collectors.toMap( ScriptMethodArg::value, a -> a ) ); + final List args = new ArrayList<>(); + Arrays.stream( m.getParameters() ).forEach( p -> { + if ( !p.isNamePresent() ) + { + throw new JavaScriptGeneratorConfigException( "Could not determine name of method parameters: " + m ); + } + final String n = p.getName(); + args.add( new MethodArgInfo( n, scriptMethodArgs.remove( n ) ) ); + } ); + if ( !scriptMethodArgs.isEmpty() ) + { + throw new JavaScriptGeneratorConfigException( "Method " + name + " contains unused script method argument annotations: " + scriptMethodArgs.keySet() ); + } + + if ( methods.put( name + ":" + m.getParameterCount(), new MethodInfo( name, scriptMethod, property, void.class.equals( m.getReturnType() ), args ) ) != null ) + { + throw new JavaScriptGeneratorConfigException( "Class " + c.getName() + " contains multiple methods named " + name + " (" + m.getParameterCount() + ")" ); + } + } ); + return new TypeInfo( new TreeSet<>( properties.values() ), new TreeSet<>( methods.values() ) ); + } + + @Nonnull + private String createSha1( @Nonnull String value ) + { + try + { + final MessageDigest digest = MessageDigest.getInstance( "SHA-1" ); + return Base64.getEncoder().withoutPadding().encodeToString( digest.digest( value.getBytes( StandardCharsets.UTF_8 ) ) ); + } + catch ( NoSuchAlgorithmException e ) + { + throw new JavaScriptGeneratorConfigException( e.getMessage(), e ); + } + } + + private static class ScriptTypeInfo + { + private final Class annotatedClass; + + private final ScriptType scriptType; + + public ScriptTypeInfo( @Nonnull Class annotatedClass, @Nonnull ScriptType scriptType ) + { + this.annotatedClass = annotatedClass; + this.scriptType = scriptType; + } + + @Nonnull + public Class getAnnotatedClass() + { + return annotatedClass; + } + + @Nonnull + public ScriptType getScriptType() + { + return scriptType; + } + } +} diff --git a/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/MethodArgInfo.java b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/MethodArgInfo.java new file mode 100644 index 00000000..f8809449 --- /dev/null +++ b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/MethodArgInfo.java @@ -0,0 +1,59 @@ +package org.dhis2.fhir.adapter.scriptable.generator; + +/* + * Copyright (c) 2004-2018, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +class MethodArgInfo +{ + private final String name; + + private final ScriptMethodArg scriptMethodArg; + + public MethodArgInfo( @Nonnull String name, @Nullable ScriptMethodArg scriptMethodArg ) + { + this.name = name; + this.scriptMethodArg = scriptMethodArg; + } + + @Nonnull + public String getName() + { + return name; + } + + @Nullable + public ScriptMethodArg getScriptMethodArg() + { + return scriptMethodArg; + } +} diff --git a/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/MethodInfo.java b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/MethodInfo.java new file mode 100644 index 00000000..b8706b20 --- /dev/null +++ b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/MethodInfo.java @@ -0,0 +1,90 @@ +package org.dhis2.fhir.adapter.scriptable.generator; + +/* + * Copyright (c) 2004-2018, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; + +import javax.annotation.Nonnull; +import java.util.List; + +class MethodInfo implements Comparable +{ + private final String name; + + private final ScriptMethod scriptMethod; + + private final boolean property; + + private final boolean voidMethod; + + private final List args; + + public MethodInfo( @Nonnull String name, @Nonnull ScriptMethod scriptMethod, boolean property, boolean voidMethod, @Nonnull List args ) + { + this.name = name; + this.scriptMethod = scriptMethod; + this.property = property; + this.voidMethod = voidMethod; + this.args = args; + } + + @Nonnull + public String getName() + { + return name; + } + + @Nonnull + public ScriptMethod getScriptMethod() + { + return scriptMethod; + } + + public boolean isProperty() + { + return property; + } + + public boolean isVoidMethod() + { + return voidMethod; + } + + @Nonnull + public List getArgs() + { + return args; + } + + @Override + public int compareTo( @Nonnull MethodInfo o ) + { + return name.compareTo( o.name ); + } +} diff --git a/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/PropertyInfo.java b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/PropertyInfo.java new file mode 100644 index 00000000..ebae8cfc --- /dev/null +++ b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/PropertyInfo.java @@ -0,0 +1,94 @@ +package org.dhis2.fhir.adapter.scriptable.generator; + +/* + * Copyright (c) 2004-2018, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; + +import javax.annotation.Nonnull; + +class PropertyInfo implements Comparable +{ + private final String name; + + private ScriptMethod scriptMethod; + + private boolean read; + + private boolean write; + + public PropertyInfo( @Nonnull String name, @Nonnull ScriptMethod scriptMethod ) + { + this.name = name; + } + + @Nonnull + public String getName() + { + return name; + } + + @Nonnull + public ScriptMethod getScriptMethod() + { + return scriptMethod; + } + + public boolean isRead() + { + return read; + } + + public PropertyInfo setRead( @Nonnull ScriptMethod scriptMethod ) + { + this.scriptMethod = scriptMethod; + this.read = true; + return this; + } + + public boolean isWrite() + { + return write; + } + + public PropertyInfo setWrite( @Nonnull ScriptMethod scriptMethod ) + { + if ( this.scriptMethod == null ) + { + this.scriptMethod = scriptMethod; + } + this.write = true; + return this; + } + + @Override + public int compareTo( @Nonnull PropertyInfo o ) + { + return name.compareTo( o.name ); + } +} diff --git a/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/TypeInfo.java b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/TypeInfo.java new file mode 100644 index 00000000..102d27f7 --- /dev/null +++ b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/TypeInfo.java @@ -0,0 +1,57 @@ +package org.dhis2.fhir.adapter.scriptable.generator; + +/* + * Copyright (c) 2004-2018, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import javax.annotation.Nonnull; +import java.util.Set; + +class TypeInfo +{ + private final Set propertyInfo; + + private final Set methodInfo; + + public TypeInfo( @Nonnull Set propertyInfo, @Nonnull Set methodInfo ) + { + this.propertyInfo = propertyInfo; + this.methodInfo = methodInfo; + } + + @Nonnull + public Set getPropertyInfo() + { + return propertyInfo; + } + + @Nonnull + public Set getMethodInfo() + { + return methodInfo; + } +} diff --git a/common/src/main/resources/dhis2-license.txt b/common/src/main/resources/dhis2-license.txt new file mode 100644 index 00000000..5a184b6b --- /dev/null +++ b/common/src/main/resources/dhis2-license.txt @@ -0,0 +1,24 @@ +Copyright (c) 2004-2018, University of Oslo +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the HISP project nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/DhisBasePackage.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/DhisBasePackage.java new file mode 100644 index 00000000..aab5ed9a --- /dev/null +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/DhisBasePackage.java @@ -0,0 +1,38 @@ +package org.dhis2.fhir.adapter.dhis; + +/* + * Copyright (c) 2004-2018, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Marker interface that is used to reference package as base package. + * + * @author volsch + */ +public interface DhisBasePackage +{ +} diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataElement.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataElement.java index 52a6acb8..a0dae2fe 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataElement.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataElement.java @@ -28,8 +28,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.model.ValueType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; /** * Contains read-only access to a DHIS2 Data Element. Implementations must guarantee diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataValue.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataValue.java index 092ab171..7e3782c3 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataValue.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/DataValue.java @@ -28,7 +28,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import java.time.ZonedDateTime; diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImmutableDataElement.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImmutableDataElement.java index 80979fba..31570d67 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImmutableDataElement.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/ImmutableDataElement.java @@ -31,8 +31,8 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.model.ValueType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nonnull; import java.io.Serializable; diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/Option.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/Option.java index af3a6ac9..54e787a1 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/Option.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/Option.java @@ -28,7 +28,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; +import org.dhis2.fhir.adapter.scriptable.Scriptable; /** * Contains read-only access to a DHIS2 Option that belong to a DHIS2 Option Set. 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 46b049d5..74b7fd06 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 @@ -28,7 +28,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import java.util.List; diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/Reference.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/Reference.java index b614516e..108c47c1 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/Reference.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/model/Reference.java @@ -32,6 +32,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.commons.lang3.StringUtils; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptType; import org.dhis2.fhir.adapter.validator.EnumValue; import javax.annotation.Nonnull; @@ -48,6 +50,7 @@ * * @author volsch */ +@ScriptType( value = "Reference", description = "Reference to an entry that is stored on DHIS2 (by ID, unique name or unique code)." ) public class Reference implements Serializable { private static final long serialVersionUID = 6049184293580457755L; @@ -85,12 +88,14 @@ public Reference( @Nonnull @JsonProperty( "value" ) String name, @Nonnull @JsonP * @return the code or name to which the reference refers to. */ @Nonnull + @ScriptMethod( description = "Returns the value of the reference (ID, unique code or unique name)." ) public String getValue() { return value; } @Nonnull + @ScriptMethod( description = "Returns the type of the reference (the ID, unique code or unique name)." ) public ReferenceType getType() { return type; @@ -103,6 +108,7 @@ public boolean isValid() } @Override + @ScriptMethod public boolean equals( Object o ) { if ( this == o ) return true; @@ -119,6 +125,7 @@ public int hashCode() } @Override + @ScriptMethod( description = "Returns the string representation of the reference (type and value separated by colon character)." ) public String toString() { return type + ":" + value; diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/Program.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/Program.java index df2ba552..829e5f8d 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/Program.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/Program.java @@ -28,8 +28,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.dhis.model.Reference; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStage.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStage.java index 3ae5db5b..6f63478d 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStage.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStage.java @@ -28,8 +28,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.dhis.model.Reference; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStageDataElement.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStageDataElement.java index bb8b1084..58f6b1ae 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStageDataElement.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStageDataElement.java @@ -28,8 +28,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.dhis.model.WritableDataElement; +import org.dhis2.fhir.adapter.scriptable.Scriptable; /** * Contains read-only access to the DHIS2 Program Stage Data Element. Implementations diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramTrackedEntityAttribute.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramTrackedEntityAttribute.java index 654199e7..a37a8e4a 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramTrackedEntityAttribute.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramTrackedEntityAttribute.java @@ -28,9 +28,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.dhis.tracker.trackedentity.TrackedEntityAttribute; import org.dhis2.fhir.adapter.model.ValueType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; /** * Contains read-only access to a Tracked Entity Attribute that belongs to a DHIS2 diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/ImmutableTrackedEntityType.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/ImmutableTrackedEntityType.java index f46e3b4a..14cc2369 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/ImmutableTrackedEntityType.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/ImmutableTrackedEntityType.java @@ -31,8 +31,8 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.dhis.model.Reference; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/TrackedEntityAttribute.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/TrackedEntityAttribute.java index a7642232..9ffa8a87 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/TrackedEntityAttribute.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/TrackedEntityAttribute.java @@ -28,9 +28,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.dhis.model.OptionSet; import org.dhis2.fhir.adapter.model.ValueType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; @Scriptable public interface TrackedEntityAttribute diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/TrackedEntityType.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/TrackedEntityType.java index c0c1d6b7..a948035d 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/TrackedEntityType.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/TrackedEntityType.java @@ -28,8 +28,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.dhis.model.Reference; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/TrackedEntityTypeAttribute.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/TrackedEntityTypeAttribute.java index 2852e055..c9d41fb9 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/TrackedEntityTypeAttribute.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/TrackedEntityTypeAttribute.java @@ -28,8 +28,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.model.ValueType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; @Scriptable public interface TrackedEntityTypeAttribute diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3AddressFhirToDhisTransformerUtils.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3AddressFhirToDhisTransformerUtils.java index 3fa99103..ae20e104 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3AddressFhirToDhisTransformerUtils.java +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3AddressFhirToDhisTransformerUtils.java @@ -29,10 +29,10 @@ */ import org.apache.commons.lang3.StringUtils; -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.model.FhirVersion; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; import org.dhis2.fhir.adapter.fhir.transform.impl.util.AbstractAddressFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.dstu3.model.Address; import org.hl7.fhir.dstu3.model.PrimitiveType; import org.hl7.fhir.instance.model.api.ICompositeType; @@ -61,12 +61,6 @@ public Set getFhirVersions() return FhirVersion.DSTU3_ONLY; } - @Override - public boolean hasPrimaryAddress( @Nonnull List addresses ) - { - return getOptionalPrimaryAddress( addresses ).isPresent(); - } - @Nullable @Override public ICompositeType getPrimaryAddress( @Nonnull List addresses ) diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3CodeFhirToDhisTransformerUtils.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3CodeFhirToDhisTransformerUtils.java index 5840ece9..42d890b2 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3CodeFhirToDhisTransformerUtils.java +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3CodeFhirToDhisTransformerUtils.java @@ -29,7 +29,6 @@ */ import com.google.common.collect.Sets; -import org.dhis2.fhir.adapter.Scriptable; 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; @@ -38,6 +37,7 @@ import org.dhis2.fhir.adapter.fhir.script.ScriptArgUtils; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; import org.dhis2.fhir.adapter.fhir.transform.impl.util.AbstractCodeFhirToDhisTransformerUtils; +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.instance.model.api.ICompositeType; diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3ContactPointFhirToDhisTransformerUtils.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3ContactPointFhirToDhisTransformerUtils.java index 03df9cec..301a8178 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3ContactPointFhirToDhisTransformerUtils.java +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3ContactPointFhirToDhisTransformerUtils.java @@ -28,10 +28,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.model.FhirVersion; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; import org.dhis2.fhir.adapter.fhir.transform.impl.util.AbstractContactPointFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.dstu3.model.ContactPoint; import org.hl7.fhir.instance.model.api.ICompositeType; import org.springframework.stereotype.Component; diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3DateTimeFhirToDhisTransformerUtils.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3DateTimeFhirToDhisTransformerUtils.java index 2b157b63..48e6af32 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3DateTimeFhirToDhisTransformerUtils.java +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3DateTimeFhirToDhisTransformerUtils.java @@ -29,10 +29,10 @@ */ import ca.uhn.fhir.model.api.TemporalPrecisionEnum; -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.model.FhirVersion; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; import org.dhis2.fhir.adapter.fhir.transform.impl.util.AbstractDateTimeFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.dhis2.fhir.adapter.util.CastUtils; import org.hl7.fhir.dstu3.model.BaseDateTimeType; import org.hl7.fhir.dstu3.model.Period; @@ -88,11 +88,7 @@ public boolean isValidNow( @Nullable ICompositeType period ) final Period p = (Period) period; final Date now = new Date(); // start will be ignored since there may be no further notification about that event - if ( (p.getEnd() != null) && now.after( p.getEnd() ) ) - { - return false; - } - return true; + return (p.getEnd() == null) || !now.after( p.getEnd() ); } @Override diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3FhirClientFhirToDhisTransformerUtils.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3FhirClientFhirToDhisTransformerUtils.java index 7db43f82..fb0c9b32 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3FhirClientFhirToDhisTransformerUtils.java +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3FhirClientFhirToDhisTransformerUtils.java @@ -29,12 +29,12 @@ */ import ca.uhn.fhir.context.FhirContext; -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.metadata.repository.RemoteSubscriptionResourceRepository; 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.impl.util.AbstractFhirClientFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.dstu3.model.Bundle; import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent; import org.hl7.fhir.dstu3.model.Bundle.BundleLinkComponent; diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3GeoFhirToDhisTransformerUtils.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3GeoFhirToDhisTransformerUtils.java index e55bb377..7a348cbf 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3GeoFhirToDhisTransformerUtils.java +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3GeoFhirToDhisTransformerUtils.java @@ -29,13 +29,13 @@ */ import ca.uhn.fhir.model.api.IElement; -import org.dhis2.fhir.adapter.Scriptable; 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.impl.util.AbstractGeoFhirToDhisTransformerUtils; import org.dhis2.fhir.adapter.geo.Location; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.dstu3.model.DecimalType; import org.hl7.fhir.dstu3.model.Element; import org.hl7.fhir.dstu3.model.Extension; diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3HumanNameFhirToDhisTransformerUtils.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3HumanNameFhirToDhisTransformerUtils.java index d8287e3e..4a44be0d 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3HumanNameFhirToDhisTransformerUtils.java +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3HumanNameFhirToDhisTransformerUtils.java @@ -28,10 +28,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.model.FhirVersion; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; import org.dhis2.fhir.adapter.fhir.transform.impl.util.AbstractHumanNameFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.dstu3.model.HumanName; import org.hl7.fhir.dstu3.model.PrimitiveType; import org.hl7.fhir.instance.model.api.ICompositeType; @@ -71,12 +71,6 @@ public String getSingleGiven( @Nullable ICompositeType humanName ) return String.join( DEFAULT_GIVEN_DELIMITER, ((HumanName) humanName).getGiven().stream().map( PrimitiveType::getValue ).collect( Collectors.toList() ) ); } - @Override - public boolean hasPrimaryName( @Nonnull List names ) - { - return getOptionalPrimaryName( names ).isPresent(); - } - @Override @Nullable public HumanName getPrimaryName( @Nonnull List names ) diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3IdentifierFhirToDhisTransformerUtils.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3IdentifierFhirToDhisTransformerUtils.java index 1eb067de..e16f9d19 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3IdentifierFhirToDhisTransformerUtils.java +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3IdentifierFhirToDhisTransformerUtils.java @@ -28,11 +28,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.model.FhirVersion; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; import org.dhis2.fhir.adapter.fhir.transform.impl.util.AbstractIdentifierFhirToDhisTransformerUtils; import org.dhis2.fhir.adapter.fhir.transform.impl.util.ReferenceFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.dstu3.model.Identifier; import org.hl7.fhir.instance.model.api.IDomainResource; import org.springframework.stereotype.Component; diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3ImmunizationFhirToDhisTransformerUtils.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3ImmunizationFhirToDhisTransformerUtils.java index 3ddf220a..4cb570e7 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3ImmunizationFhirToDhisTransformerUtils.java +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3ImmunizationFhirToDhisTransformerUtils.java @@ -28,11 +28,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; 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.impl.util.AbstractImmunizationFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.dstu3.model.Immunization; import org.hl7.fhir.instance.model.api.IDomainResource; import org.springframework.stereotype.Component; diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3ObservationFhirToDhisTransformerUtils.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3ObservationFhirToDhisTransformerUtils.java index 6e2e7f1b..7cd1c3d8 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3ObservationFhirToDhisTransformerUtils.java +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3ObservationFhirToDhisTransformerUtils.java @@ -28,10 +28,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.model.FhirVersion; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; import org.dhis2.fhir.adapter.fhir.transform.impl.util.AbstractObservationFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.dstu3.model.Observation; import org.hl7.fhir.dstu3.model.Observation.ObservationComponentComponent; import org.hl7.fhir.dstu3.model.ResourceType; diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3OrganizationFhirToDhisTransformerUtils.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3OrganizationFhirToDhisTransformerUtils.java index 40ccec49..ac889dfc 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3OrganizationFhirToDhisTransformerUtils.java +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3OrganizationFhirToDhisTransformerUtils.java @@ -28,7 +28,6 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.dhis.orgunit.OrganisationUnitService; import org.dhis2.fhir.adapter.fhir.metadata.repository.RemoteSubscriptionResourceRepository; import org.dhis2.fhir.adapter.fhir.model.FhirVersion; @@ -36,6 +35,7 @@ import org.dhis2.fhir.adapter.fhir.repository.RemoteHierarchicallyFhirRepository; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; import org.dhis2.fhir.adapter.fhir.transform.impl.util.AbstractOrganizationFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.dstu3.model.Bundle; import org.hl7.fhir.dstu3.model.Organization; import org.hl7.fhir.instance.model.api.IBaseBundle; diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3PatientFhirToDhisTransformerUtils.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3PatientFhirToDhisTransformerUtils.java index 814ebcc6..1feac69c 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3PatientFhirToDhisTransformerUtils.java +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3PatientFhirToDhisTransformerUtils.java @@ -28,11 +28,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; 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.impl.util.AbstractPatientFhirToDhisTransformerUtils; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.dstu3.model.Address; import org.hl7.fhir.dstu3.model.Extension; import org.hl7.fhir.dstu3.model.Patient; diff --git a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3VitalSignFhirToDhisTransformerUtils.java b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3VitalSignFhirToDhisTransformerUtils.java index 21809c28..2f9782ba 100644 --- a/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3VitalSignFhirToDhisTransformerUtils.java +++ b/fhir-dstu3/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/dstu3/Dstu3VitalSignFhirToDhisTransformerUtils.java @@ -28,13 +28,13 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; 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.impl.util.AbstractVitalSignFhirToDhisTransformerUtils; import org.dhis2.fhir.adapter.model.WeightUnit; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.dstu3.model.Quantity; import org.hl7.fhir.instance.model.api.ICompositeType; import org.springframework.stereotype.Component; diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/FhirBasePackage.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/FhirBasePackage.java new file mode 100644 index 00000000..463378aa --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/FhirBasePackage.java @@ -0,0 +1,38 @@ +package org.dhis2.fhir.adapter.fhir; + +/* + * Copyright (c) 2004-2018, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Marker interface that is used to reference package as base package. + * + * @author volsch + */ +public interface FhirBasePackage +{ +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/model/SystemCodeValue.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/model/SystemCodeValue.java index 720232f0..96644bb4 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/model/SystemCodeValue.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/model/SystemCodeValue.java @@ -28,9 +28,20 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; + import java.io.Serializable; import java.util.Objects; +/** + * The combination of system URI and code. + * + * @author volsch + */ +@Scriptable +@ScriptType( value = "SystemCodeValue", description = "Contains the combination of system URI and code." ) public class SystemCodeValue implements Serializable { private static final long serialVersionUID = -4751270623619799949L; @@ -47,17 +58,20 @@ public SystemCodeValue( String system, String code ) this.code = code; } + @ScriptMethod( description = "Returns the system URI." ) public String getSystem() { return system; } + @ScriptMethod( description = "Returns the code." ) public String getCode() { return code; } @Override + @ScriptMethod public boolean equals( Object o ) { if ( this == o ) return true; @@ -74,6 +88,7 @@ public int hashCode() } @Override + @ScriptMethod( description = "Returns the string representation of system URI and code. The string representation contains the system URI and the code separated by a pipe character (as used by FHIR searches)." ) public String toString() { return (system == null) ? code : (system + SEPARATOR + code); diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/FhirRepositoryImpl.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/FhirRepositoryImpl.java index 23bb29ee..ecb1d88b 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/FhirRepositoryImpl.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/repository/impl/FhirRepositoryImpl.java @@ -381,6 +381,7 @@ protected boolean saveInternally( @Nonnull RemoteSubscriptionResource subscripti fhirRequest.setRemoteSubscriptionResourceId( subscriptionResource.getId() ); fhirRequest.setVersion( subscriptionResource.getRemoteSubscription().getFhirVersion() ); fhirRequest.setParameters( ArrayListMultimap.create() ); + fhirRequest.setRemoteSubscriptionCode( subscriptionResource.getRemoteSubscription().getCode() ); fhirRequest.setResourceSystemsByType( systems.stream() .map( s -> new ResourceSystem( s.getFhirResourceType(), s.getSystem().getSystemUri(), s.getCodePrefix() ) ) .collect( Collectors.toMap( ResourceSystem::getFhirResourceType, rs -> rs ) ) ); diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/FhirToDhisTransformerContext.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/FhirToDhisTransformerContext.java index 6262e131..2380984d 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/FhirToDhisTransformerContext.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/FhirToDhisTransformerContext.java @@ -28,22 +28,25 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.dhis.model.Reference; import org.dhis2.fhir.adapter.dhis.model.ReferenceType; import org.dhis2.fhir.adapter.fhir.transform.impl.TransformerScriptException; import org.dhis2.fhir.adapter.fhir.transform.model.FhirRequest; -import org.hl7.fhir.instance.model.api.IBaseResource; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.time.ZonedDateTime; -import java.util.List; @Scriptable +@ScriptType( value = "Context", var = "context", description = "The context of the current transformation." ) public interface FhirToDhisTransformerContext { @Nonnull + @ScriptMethod( description = "Returns the FHIR request (type FhirRequest) that causes the current transformation execution." ) FhirRequest getFhirRequest(); /** @@ -57,13 +60,17 @@ public interface FhirToDhisTransformerContext * @throws TransformerScriptException thrown if the specified reference type is invalid. */ @Nullable + @ScriptMethod( description = "Returns a reference to a DHIS2 entry (type Reference).", + args = { + @ScriptMethodArg( value = "value", description = "The value of the reference (the ID, unique code or unique name of the DHIS2 entry)." ), + @ScriptMethodArg( value = "referenceType", description = "The reference type (ID, CODE, NAME)." ) + }, + returnDescription = "The created reference." ) Reference createReference( @Nullable String value, @Nonnull Object referenceType ) throws TransformerScriptException; @Nonnull - List createFhirResourceList(); - - @Nonnull + @ScriptMethod( description = "Returns the current timestamp as date/time.", returnDescription = "The current timestamp as date/time." ) ZonedDateTime now(); /** @@ -71,9 +78,6 @@ Reference createReference( @Nullable String value, @Nonnull Object referenceType */ boolean isCreationDisabled(); - @Nonnull - T failIfNull( @Nonnull String message, @Nullable T value ) throws TransformerDataException; - /** * Ends the execution of the script with the specified message. This method can be used if the * received data does not match any expectations. @@ -81,5 +85,7 @@ Reference createReference( @Nullable String value, @Nonnull Object referenceType * @param message the message that includes the reason why the transformations failed. * @throws TransformerDataException the thrown exception with the specified message. */ + @ScriptMethod( description = "Causes that the current transformation will fail with the specified message due to invalid data.", + args = @ScriptMethodArg( value = "message", description = "The reason that specifies why the transformation data is invalid." ) ) void fail( @Nonnull String message ) throws TransformerDataException; } diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/FhirToDhisTransformerContextImpl.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/FhirToDhisTransformerContextImpl.java index 1ab45cb9..37304d5f 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/FhirToDhisTransformerContextImpl.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/FhirToDhisTransformerContextImpl.java @@ -34,14 +34,11 @@ import org.dhis2.fhir.adapter.fhir.transform.TransformerDataException; import org.dhis2.fhir.adapter.fhir.transform.model.FhirRequest; import org.dhis2.fhir.adapter.fhir.transform.model.ImmutableFhirRequest; -import org.hl7.fhir.instance.model.api.IBaseResource; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.Serializable; import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.List; public class FhirToDhisTransformerContextImpl implements FhirToDhisTransformerContext, Serializable { @@ -85,13 +82,6 @@ public Reference createReference( @Nullable String value, @Nonnull Object refere return new Reference( value, rt ); } - @Nonnull - @Override - public List createFhirResourceList() - { - return new ArrayList<>(); - } - @Nonnull @Override public ZonedDateTime now() @@ -105,17 +95,6 @@ public boolean isCreationDisabled() return creationDisabled; } - @Nonnull - @Override - public T failIfNull( @Nonnull String message, @Nullable T value ) throws TransformerDataException - { - if ( value == null ) - { - throw new TransformerDataException( message ); - } - return value; - } - @Override public void fail( @Nonnull String message ) throws TransformerDataException { diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/ScriptedDhisResource.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/ScriptedDhisResource.java index 56a368cc..711bd856 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/ScriptedDhisResource.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/ScriptedDhisResource.java @@ -28,8 +28,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.transform.TransformerException; +import org.dhis2.fhir.adapter.scriptable.Scriptable; @Scriptable public interface ScriptedDhisResource diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/TransformationConfig.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/TransformationConfig.java index 77c252f6..e7b3423b 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/TransformationConfig.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/TransformationConfig.java @@ -28,10 +28,14 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import org.dhis2.fhir.adapter.dhis.DhisBasePackage; +import org.dhis2.fhir.adapter.fhir.FhirBasePackage; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; import org.dhis2.fhir.adapter.fhir.script.impl.ThreadLocalScriptExecutionContext; +import org.dhis2.fhir.adapter.geo.GeoBasePackage; import org.dhis2.fhir.adapter.script.ScriptCompiler; import org.dhis2.fhir.adapter.script.impl.ScriptCompilerImpl; +import org.dhis2.fhir.adapter.scriptable.generator.JavaScriptGeneratorConfig; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -87,4 +91,14 @@ protected ScriptCompiler scriptCompiler() { return new ScriptCompilerImpl( getScriptEngineName() ); } + + @Bean + @Nonnull + protected JavaScriptGeneratorConfig javaScriptGeneratorConfig() + { + return new JavaScriptGeneratorConfig().setBasePackageClasses( + GeoBasePackage.class, + DhisBasePackage.class, + FhirBasePackage.class ); + } } diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ImmutableScriptedEnrollment.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ImmutableScriptedEnrollment.java index 1da4bea4..6c419e31 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ImmutableScriptedEnrollment.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ImmutableScriptedEnrollment.java @@ -28,9 +28,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.transform.TransformerException; import org.dhis2.fhir.adapter.geo.Location; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ImmutableScriptedEvent.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ImmutableScriptedEvent.java index ab55af63..24777ec8 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ImmutableScriptedEvent.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ImmutableScriptedEvent.java @@ -29,10 +29,10 @@ */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.dhis.tracker.program.EventStatus; import org.dhis2.fhir.adapter.fhir.transform.TransformerException; import org.dhis2.fhir.adapter.geo.Location; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ScriptedEnrollment.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ScriptedEnrollment.java index ca080e79..72eb94ca 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ScriptedEnrollment.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ScriptedEnrollment.java @@ -28,9 +28,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.transform.impl.ScriptedDhisResource; import org.dhis2.fhir.adapter.geo.Location; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nullable; import java.time.ZonedDateTime; diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ScriptedEvent.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ScriptedEvent.java index 429b53ec..63ae33d9 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ScriptedEvent.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/ScriptedEvent.java @@ -28,10 +28,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.dhis.tracker.program.EventStatus; import org.dhis2.fhir.adapter.fhir.transform.impl.ScriptedDhisResource; import org.dhis2.fhir.adapter.geo.Location; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nullable; import java.time.ZonedDateTime; diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/WritableScriptedEnrollment.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/WritableScriptedEnrollment.java index c4a62297..9b31049b 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/WritableScriptedEnrollment.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/WritableScriptedEnrollment.java @@ -28,7 +28,6 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.dhis.converter.ValueConverter; import org.dhis2.fhir.adapter.dhis.tracker.program.Enrollment; import org.dhis2.fhir.adapter.dhis.tracker.program.Program; @@ -37,6 +36,7 @@ import org.dhis2.fhir.adapter.fhir.transform.impl.util.ScriptedDateTimeUtils; import org.dhis2.fhir.adapter.geo.Location; import org.dhis2.fhir.adapter.model.ValueType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.dhis2.fhir.adapter.util.DateTimeUtils; import javax.annotation.Nonnull; diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/WritableScriptedEvent.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/WritableScriptedEvent.java index 9069325a..030d8c8e 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/WritableScriptedEvent.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/program/WritableScriptedEvent.java @@ -29,7 +29,6 @@ */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.converter.ConversionException; import org.dhis2.fhir.adapter.dhis.converter.ValueConverter; import org.dhis2.fhir.adapter.dhis.model.Reference; @@ -45,6 +44,7 @@ import org.dhis2.fhir.adapter.fhir.transform.impl.util.ScriptedDateTimeUtils; import org.dhis2.fhir.adapter.geo.Location; import org.dhis2.fhir.adapter.model.ValueType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/trackedentity/ScriptedTrackedEntityInstance.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/trackedentity/ScriptedTrackedEntityInstance.java index 45f314c8..478643ca 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/trackedentity/ScriptedTrackedEntityInstance.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/trackedentity/ScriptedTrackedEntityInstance.java @@ -28,9 +28,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.dhis.model.Reference; import org.dhis2.fhir.adapter.fhir.transform.impl.ScriptedDhisResource; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/trackedentity/WritableScriptedTrackedEntityInstance.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/trackedentity/WritableScriptedTrackedEntityInstance.java index 3875edd0..7b2bdb9d 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/trackedentity/WritableScriptedTrackedEntityInstance.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/trackedentity/WritableScriptedTrackedEntityInstance.java @@ -28,7 +28,6 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.converter.ConversionException; import org.dhis2.fhir.adapter.dhis.converter.ValueConverter; import org.dhis2.fhir.adapter.dhis.model.Option; @@ -44,6 +43,10 @@ import org.dhis2.fhir.adapter.fhir.transform.TransformerMappingException; import org.dhis2.fhir.adapter.fhir.transform.impl.util.ScriptedDateTimeUtils; 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.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -52,7 +55,15 @@ import java.util.Objects; import java.util.Optional; +/** + * Writable scripted tracked entity instance that is used in evaluation and transformation + * scripts and prevents accesses to the tracked entity instance domain object. + * + * @author volsch + */ @Scriptable +@ScriptType( value = "TrackedEntityInstance", var = "trackedEntityInstance", transformDataType = "DHIS_TRACKED_ENTITY_INSTANCE", + description = "Tracked entity instance. If tracked entity instance is not new and will be modified, it will be persisted." ) public class WritableScriptedTrackedEntityInstance implements ScriptedTrackedEntityInstance { private final TrackedEntityAttributes trackedEntityAttributes; @@ -74,6 +85,7 @@ public WritableScriptedTrackedEntityInstance( @Nonnull FhirToDhisTransformerCont } @Override + @ScriptMethod( description = "Returns if the tracked entity instance is new ans has not yet been saved on DHIS2." ) public boolean isNewResource() { return trackedEntityInstance.isNewResource(); @@ -81,6 +93,7 @@ public boolean isNewResource() @Nullable @Override + @ScriptMethod( description = "Returns the ID of the tracked entity instance on DHIS2. Return null if the instance is new." ) public String getId() { return trackedEntityInstance.getId(); @@ -88,12 +101,14 @@ public String getId() @Nonnull @Override + @ScriptMethod( description = "Returns the ID of the tracked entity type to which this tracked entity instance belongs to on DHIS2." ) public String getTypeId() { return trackedEntityType.getId(); } @Nonnull + @ScriptMethod( description = "Returns the national identifier of the tracked entity instance." ) public String getIdentifier() { return trackedEntityInstance.getIdentifier(); @@ -101,11 +116,13 @@ public String getIdentifier() @Override @Nullable + @ScriptMethod( description = "Returns the organization unit ID of the organization unit to which this tracked entity instance belongs to on DHIS2." ) public String getOrganizationUnitId() { return trackedEntityInstance.getOrgUnitId(); } + @ScriptMethod( description = "Sets the organization unit ID of the organization unit to which this tracked entity instance belongs to on DHIS2 (must not be null)." ) public boolean setOrganizationUnitId( @Nullable String id ) throws TransformerException { if ( id == null ) @@ -121,11 +138,15 @@ public boolean setOrganizationUnitId( @Nullable String id ) throws TransformerEx } @Nullable + @ScriptMethod( description = "Returns the coordinates (normally longitude and latitude) of the tracked entity instance." ) public String getCoordinates() { return trackedEntityInstance.getCoordinates(); } + @ScriptMethod( description = "Sets the coordinates of the tracked entity instance. This might be a string representation of the coordinates or a location object.", + returnDescription = "Returns true each time (at end of script return of true can be avoided).", + args = @ScriptMethodArg( value = "coordinates", description = "The coordinates as string representation, location object or null." ) ) public boolean setCoordinates( @Nullable Object coordinates ) { final String convertedValue; @@ -145,11 +166,25 @@ public boolean setCoordinates( @Nullable Object coordinates ) return true; } + @ScriptMethod( description = "Sets the value of a tracked entity attribute.", + returnDescription = "Returns true each time (at end of script return of true can be avoided).", + args = { + @ScriptMethodArg( value = "attributeReference", description = "The reference object to the tracked entity attribute." ), + @ScriptMethodArg( value = "value", description = "The value that should be set. The value will be converted to the required type automatically (if possible)." ), + } ) public boolean setValue( @Nonnull Reference attributeReference, @Nullable Object value ) throws TransformerException { return setValue( attributeReference, value, null ); } + @ScriptMethod( description = "Sets the value of a tracked entity attribute. " + + "This will be skipped when the specified last updated date is before the current last updated data and the user which has last modified the tracked entity was not the adapter itself.", + returnDescription = "Returns only true if updating the value has not been skipped since the specified last updated date is before the current last updated date.", + args = { + @ScriptMethodArg( value = "attributeReference", description = "The reference object to the tracked entity attribute." ), + @ScriptMethodArg( value = "value", description = "The value that should be set. The value will be converted to the required type automatically (if possible)." ), + @ScriptMethodArg( value = "lastUpdated", description = "The last updated timestamp of the data that should be assigned to the tracked entity. This value can be null if check should not be made." ) + } ) public boolean setValue( @Nonnull Reference attributeReference, @Nullable Object value, @Nullable Object lastUpdated ) throws TransformerException { final TrackedEntityAttribute attribute = trackedEntityAttributes.getOptional( attributeReference ).orElseThrow( () -> @@ -158,11 +193,25 @@ public boolean setValue( @Nonnull Reference attributeReference, @Nullable Object return setValue( attribute, typeAttribute, value, ScriptedDateTimeUtils.toZonedDateTime( lastUpdated, valueConverter ) ); } + @ScriptMethod( description = "Sets the value of a tracked entity attribute. If the specified attribute reference is null, nothing will be done.", + returnDescription = "Returns true each time (at end of script return of true can be avoided).", + args = { + @ScriptMethodArg( value = "attributeReference", description = "The reference object to the tracked entity attribute (can be null)." ), + @ScriptMethodArg( value = "value", description = "The value that should be set. The value will be converted to the required type automatically (if possible)." ), + } ) public boolean setOptionalValue( @Nullable Reference attributeReference, @Nullable Object value ) throws TransformerException { return setOptionalValue( attributeReference, value, null ); } + @ScriptMethod( description = "Sets the value of a tracked entity attribute. If the specified attribute reference is null, nothing will be done. " + + "This will be skipped when the specified last updated date is before the current last updated data and the user which has last modified the tracked entity was not the adapter itself.", + returnDescription = "Returns only true if updating the value has not been skipped since the specified last updated date is before the current last updated date.", + args = { + @ScriptMethodArg( value = "attributeReference", description = "The reference object to the tracked entity attribute (can be null)." ), + @ScriptMethodArg( value = "value", description = "The value that should be set. The value will be converted to the required type automatically (if possible)." ), + @ScriptMethodArg( value = "lastUpdated", description = "The last updated timestamp of the data that should be assigned to the tracked entity. This value can be null if check should not be made." ) + } ) public boolean setOptionalValue( @Nullable Reference attributeReference, @Nullable Object value, @Nullable Object lastUpdated ) throws TransformerException { if ( attributeReference != null ) @@ -180,6 +229,7 @@ public void initValue( @Nonnull Reference attributeReference ) @Nullable @Override + @ScriptMethod( description = "Returns the value of a tracked entity instance attribute.", args = @ScriptMethodArg( value = "attributeReference", description = "The reference object to the tracked entity attribute." ) ) public Object getValue( @Nonnull Reference attributeReference ) { final TrackedEntityAttribute attribute = getTypeAttribute( attributeReference ); @@ -275,6 +325,7 @@ protected Object getValue( @Nonnull TrackedEntityAttribute attribute ) throws Tr } @Override + @ScriptMethod( description = "Validates the content of the tracked entity instance and throws an exception if the content is invalid." ) public void validate() throws TransformerException { if ( trackedEntityInstance.getOrgUnitId() == null ) diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractAddressFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractAddressFhirToDhisTransformerUtils.java index 49bd3431..2a5d1163 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractAddressFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractAddressFhirToDhisTransformerUtils.java @@ -28,23 +28,33 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.instance.model.api.ICompositeType; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; +/** + * FHIR to DHIS2 transformer utility methods for addresses. + * + * @author volsch + */ @Scriptable +@ScriptType( value = "AddressUtils", var = AbstractAddressFhirToDhisTransformerUtils.SCRIPT_ATTR_NAME, + description = "Utilities to handle FHIR to DHIS2 transformations of addresses." ) public abstract class AbstractAddressFhirToDhisTransformerUtils extends AbstractFhirToDhisTransformerUtils { + public static final String SCRIPT_ATTR_NAME = "addressUtils"; + protected static final String DEFAULT_LINE_DELIMITER = " "; protected static final String DEFAULT_TEXT_DELIMITER = " / "; - private static final String SCRIPT_ATTR_NAME = "addressUtils"; - protected AbstractAddressFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) { super( scriptExecutionContext ); @@ -58,28 +68,46 @@ public final String getScriptAttrName() } @Nullable + @ScriptMethod( description = "Returns a single address line for the adress lines includes in the specified FHIR address. A space is used to separate the lines.", + args = @ScriptMethodArg( value = "address", description = "The FHIR address from which the address lines should be used." ), + returnDescription = "A single line for the included address lines." ) public String getSingleLine( @Nullable ICompositeType address ) { return getSingleLine( address, DEFAULT_LINE_DELIMITER ); } @Nullable + @ScriptMethod( description = "Returns a constructed text of the address that contains the address lines, the postal code, the city and the state (if available). ' / ' is used to separate the address components.", + args = @ScriptMethodArg( value = "address", description = "The FHIR address from which the address components should be used." ), + returnDescription = "The constructed address text." ) public String getConstructedText( @Nullable ICompositeType address ) { return getConstructedText( address, DEFAULT_TEXT_DELIMITER ); } - public abstract boolean hasPrimaryAddress( @Nonnull List addresses ); - @Nullable public abstract ICompositeType getPrimaryAddress( @Nonnull List addresses ); @Nullable + @ScriptMethod( description = "Returns a single address line for the adress lines includes in the specified FHIR address.", + args = { + @ScriptMethodArg( value = "address", description = "The FHIR address from which the address lines should be used." ), + @ScriptMethodArg( value = "delimiter", description = "The delimiter that should be used to separated the lines (e.g. space character)." ) + }, + returnDescription = "A single line for the included address lines." ) public abstract String getSingleLine( @Nullable ICompositeType address, @Nonnull String delimiter ); @Nullable + @ScriptMethod( description = "Returns a constructed text of the address that contains the address lines, the postal code, the city and the state (if available).", + args = { + @ScriptMethodArg( value = "address", description = "The FHIR address from which the address components should be used." ), + @ScriptMethodArg( value = "delimiter", description = "The delimiter that should be used to separated the lines (e.g. space character)." ) + }, + returnDescription = "The constructed address text." ) public abstract String getConstructedText( @Nullable ICompositeType address, @Nonnull String delimiter ); @Nullable + @ScriptMethod( description = "Returns the text representation (if included) of the address.", + args = @ScriptMethodArg( value = "address", description = "The FHIR address from which the text should be returned." ) ) public abstract String getText( @Nullable ICompositeType address ); } diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractCodeFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractCodeFhirToDhisTransformerUtils.java index 6050c372..331a2451 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractCodeFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractCodeFhirToDhisTransformerUtils.java @@ -28,7 +28,6 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; 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.ScriptVariable; @@ -44,6 +43,10 @@ import org.dhis2.fhir.adapter.fhir.transform.TransformerMappingException; import org.dhis2.fhir.adapter.fhir.transform.impl.TransformerScriptException; import org.dhis2.fhir.adapter.fhir.transform.model.ResourceSystem; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.ICompositeType; import org.hl7.fhir.instance.model.api.IDomainResource; @@ -62,10 +65,17 @@ import java.util.List; import java.util.Map; +/** + * FHIR to DHIS2 transformer utility methods for code mappings and FHIR codeable concepts. + * + * @author volsch + */ @Scriptable +@ScriptType( value = "CodeUtils", var = AbstractCodeFhirToDhisTransformerUtils.SCRIPT_ATTR_NAME, + description = "Utilities to handle FHIR to DHIS2 transformations for codes (either code mappings or extracting of codes from FHIR codeable concepts)." ) public abstract class AbstractCodeFhirToDhisTransformerUtils extends AbstractFhirToDhisTransformerUtils { - private static final String SCRIPT_ATTR_NAME = "codeUtils"; + public static final String SCRIPT_ATTR_NAME = "codeUtils"; private static final List GET_CODE_METHOD_NAMES = Collections.unmodifiableList( Arrays.asList( "getCode", "getVaccineCode" ) ); @@ -96,18 +106,45 @@ public final String getScriptAttrName() } @Nonnull + @ScriptMethod( description = "Returns all system code values that are included in the specified FHIR codeable concept.", + args = @ScriptMethodArg( value = "codeableConcept", description = "The FHIR codeable concept from which the system code values should be extracted." ), + returnDescription = "Returns a list that contains all corresponding system codes values (type SystemCodeValue)." ) public abstract List getSystemCodeValues( @Nullable ICompositeType codeableConcept ); @Nullable + @ScriptMethod( description = "Returns the code that is included in the specified codeable concept for the specified system URI.", + args = { + @ScriptMethodArg( value = "codeableConcept", description = "The codeable concept from which the code should be extracted." ), + @ScriptMethodArg( value = "system", description = "The system URI to which the returned code must be assigned to." ) + }, + returnDescription = "Returns the corresponding code." + ) public abstract String getCode( @Nullable ICompositeType codeableConcept, @Nullable String system ); + @ScriptMethod( description = "Returns if the specified FHIR codeable concept contains any enabled mapping for the specified mapping codes defined for the adapter.", + args = { + @ScriptMethodArg( value = "codeableConcept", description = "The codeable concept that should be checked." ), + @ScriptMethodArg( value = "mappingCodes", description = "Array of mapping codes that have been defined for the adapter (field code of adapter resource codes)." ) + }, + returnDescription = "Returns if the mapping code is included." + ) public abstract boolean containsMappingCode( @Nullable ICompositeType codeableConcept, @Nullable Object mappingCodes ); + @ScriptMethod( description = "Returns if the specified codeable concept contains any combination of the specified system URI and the specified code.", + args = { + @ScriptMethodArg( value = "codeableConcept", description = "The codeable concept that should be checked." ), + @ScriptMethodArg( value = "system", description = "The system URI that must be included in combination with the specified code." ), + @ScriptMethodArg( value = "code", description = "The code that must be included in combination with the specified system URI." ), + }, + returnDescription = "Returns if the code is included." ) public abstract boolean containsCode( @Nullable ICompositeType codeableConcept, @Nonnull String system, @Nonnull String code ); - @Nullable - protected abstract List getSystemCodeValues( @Nonnull IDomainResource domainResource, @Nonnull Method identifierMethod ); - + @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 ) { if ( (codeableConcept == null) || (systemCodeValues == null) ) @@ -117,15 +154,18 @@ public boolean containsAnyCode( @Nullable ICompositeType codeableConcept, @Nulla return systemCodeValues.stream().anyMatch( scv -> containsCode( codeableConcept, 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). " + + "The mapping codes are included in field code of adapter resource codes. All specified mapping codes are returned (even if there is no corresponding system code value available).", + args = @ScriptMethodArg( value = "mappingCodes", description = "The mapping codes for which the system code values should be returned." ), + returnDescription = "Returns a map where the key is each specified mapping code and the value is a list of system code values (type SystemCodeValue)." ) @Nonnull - public Map> getSystemCodeValuesByCodes( @Nullable Object[] codes ) + public Map> getSystemCodeValuesByMappingCodes( @Nullable Object mappingCodes ) { - if ( (codes == null) || (codes.length == 0) ) + if ( mappingCodes == null ) { return Collections.emptyMap(); } - - final List convertedCodes = ScriptArgUtils.extractStringArray( codes ); + final List convertedCodes = ScriptArgUtils.extractStringArray( mappingCodes ); if ( CollectionUtils.isEmpty( convertedCodes ) ) { return Collections.emptyMap(); @@ -146,19 +186,24 @@ public Map> getSystemCodeValuesByCodes( @Nullable return result; } + @ScriptMethod( description = "Extracts all system code values (type SystemCodeValue) for the codes that identify the purpose of the specified FHIR resource (e.g. observation or vaccine codes).", + args = { + @ScriptMethodArg( value = "resource", description = "The FHIR resource from which the codes should be returned." ), + }, + returnDescription = "Returns a list of system code values (type SystemCodeValue)." ) @Nullable - public List getResourceCodes( @Nullable IBaseResource baseResource ) throws TransformerException + public List getResourceCodes( @Nullable IBaseResource resource ) throws TransformerException { - if ( baseResource == null ) + if ( resource == null ) { throw new TransformerMappingException( "Cannot get codes of undefined domain resource." ); } - if ( !(baseResource instanceof IDomainResource) ) + if ( !(resource instanceof IDomainResource) ) { return null; } - final IDomainResource domainResource = (IDomainResource) baseResource; + final IDomainResource domainResource = (IDomainResource) resource; final Method method = getCodeMethod( domainResource ); if ( method != null ) { @@ -168,6 +213,14 @@ public List getResourceCodes( @Nullable IBaseResource baseResou } @ScriptExecutionRequired + @ScriptMethod( description = "Returns the mapped code (field code or if available field mappedCode of apdater resource code) for the specified FHIR resource type dependent code. " + + "As system URI the value associated with the FHIR resource type of the remote subscription system (adapter resource remoteSubscriptionSystems) of the current transformation context is used.", + args = { + @ScriptMethodArg( value = "code", description = "The code in context of the system URI for the specified FHIR resource type." ), + @ScriptMethodArg( value = "fhirResourceType", description = "The FHIR resource type (upper case letters, separated by underscores) from which the associated system URI should be taken." ), + }, + returnDescription = "The associated mapped code." ) + @Nullable public String getMappedCode( @Nullable String code, @Nonnull Object fhirResourceType ) { if ( code == null ) @@ -198,6 +251,9 @@ public String getMappedCode( @Nullable String code, @Nonnull Object fhirResource return (c.getMappedCode() == null) ? c.getCode() : c.getMappedCode(); } + @Nullable + protected abstract List getSystemCodeValues( @Nonnull IDomainResource domainResource, @Nonnull Method identifierMethod ); + @Nullable private Method getCodeMethod( @Nonnull IDomainResource domainResource ) { diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractContactPointFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractContactPointFhirToDhisTransformerUtils.java index d7c6f433..e4ebcaa1 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractContactPointFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractContactPointFhirToDhisTransformerUtils.java @@ -28,18 +28,28 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.instance.model.api.ICompositeType; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; +/** + * FHIR to DHIS2 transformer utility methods for FHIR contact points. + * + * @author volsch + */ @Scriptable +@ScriptType( value = "ContactPointUtils", var = AbstractContactPointFhirToDhisTransformerUtils.SCRIPT_ATTR_NAME, + description = "Utilities to handle FHIR to DHIS2 transformations for FHIR contact points." ) public abstract class AbstractContactPointFhirToDhisTransformerUtils extends AbstractFhirToDhisTransformerUtils { - private static final String SCRIPT_ATTR_NAME = "contactPointUtils"; + public static final String SCRIPT_ATTR_NAME = "contactPointUtils"; protected AbstractContactPointFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) { @@ -54,6 +64,9 @@ public final String getScriptAttrName() } @Nullable + @ScriptMethod( description = "Returns the phone number contact point from the specified list of contact points. If there are multiple contact points that include a phone number then it is tried to find the most appropriate contact point.", + args = @ScriptMethodArg( value = "contactPoints", description = "List of FHIR contact points from which a phone contact point should be extracted." ), + returnDescription = "An included phone number." ) public String getPhoneContactPointValue( @Nullable List contactPoints ) { return getContactPointValue( contactPoints, "phone" ); diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractDateTimeFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractDateTimeFhirToDhisTransformerUtils.java index f8eafd98..21763753 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractDateTimeFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractDateTimeFhirToDhisTransformerUtils.java @@ -28,10 +28,13 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; import org.dhis2.fhir.adapter.fhir.transform.impl.TransformerScriptException; import org.dhis2.fhir.adapter.model.DateUnit; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.instance.model.api.ICompositeType; import org.hl7.fhir.instance.model.api.IPrimitiveType; @@ -44,10 +47,17 @@ import java.time.temporal.TemporalUnit; import java.util.Date; +/** + * FHIR to DHIS2 transformer utility methods for date and time handling. + * + * @author volsch + */ @Scriptable +@ScriptType( value = "DateTimeUtils", var = AbstractDateTimeFhirToDhisTransformerUtils.SCRIPT_ATTR_NAME, + description = "Utilities for date and time handling." ) public abstract class AbstractDateTimeFhirToDhisTransformerUtils extends AbstractFhirToDhisTransformerUtils { - private static final String SCRIPT_ATTR_NAME = "dateTimeUtils"; + public static final String SCRIPT_ATTR_NAME = "dateTimeUtils"; protected AbstractDateTimeFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) { @@ -61,9 +71,15 @@ public final String getScriptAttrName() return SCRIPT_ATTR_NAME; } + @ScriptMethod( description = "Returns if the specified date/time element value has at least day precision. A date/time element value may have only year or month precision.", + args = @ScriptMethodArg( value = "dateTime", description = "The date/time element value for which the evaluation should be performed." ), + returnDescription = "Returns if the specified date/time element has at least day precision." ) public abstract boolean hasDayPrecision( @Nullable IPrimitiveType dateTime ); @Nullable + @ScriptMethod( description = "Returns a date/time value for the specified date/time element value when it has at least day precision. A date/time element value may have only year or month precision.", + args = @ScriptMethodArg( value = "dateTime", description = "The date/time element value for which the evaluation should be performed." ), + returnDescription = "Returns if the specified date/time element as date/time value or null when it has not at least day precision." ) public Date getPreciseDate( @Nullable IPrimitiveType dateTime ) { if ( (dateTime == null) || (dateTime.getValue() == null) || !hasDayPrecision( dateTime ) ) @@ -73,8 +89,10 @@ public Date getPreciseDate( @Nullable IPrimitiveType dateTime ) return dateTime.getValue(); } - @Nullable + @ScriptMethod( description = "Returns a date/time value for the specified date/time element value when it has at least day precision and is in the past. A date/time element value may have only year or month precision.", + args = @ScriptMethodArg( value = "dateTime", description = "The date/time element value for which the evaluation should be performed." ), + returnDescription = "Returns if the specified date/time element as date/time value or null when it has not at least day precision or is in the future." ) public Date getPrecisePastDate( @Nullable IPrimitiveType dateTime ) { final Date date = getPreciseDate( dateTime ); @@ -86,6 +104,14 @@ public Date getPrecisePastDate( @Nullable IPrimitiveType dateTime ) } @Nullable + @ScriptMethod( description = "Returns the age relative to the specified date/time in the specified unit.", + args = { + @ScriptMethodArg( value = "relativeDateTime", description = "The date/time value to which the age should be calculated relatively. If the date/time value is today then the age is calcualted for the current date." ), + @ScriptMethodArg( value = "dateTime", description = "The date/time value for which the age up to the relative date/time value should be calculated." ), + @ScriptMethodArg( value = "dateUnit", description = "The unit of the returned age (YEARS, MONTHS, DAYS)." ), + }, + returnDescription = "The age in the specified unit." + ) public Integer getAge( @Nonnull Object relativeDateTime, @Nullable Object dateTime, @Nonnull Object dateUnit ) { if ( dateTime == null ) @@ -106,7 +132,7 @@ public Integer getAge( @Nonnull Object relativeDateTime, @Nullable Object dateTi final LocalDate convertedRelativeDate = castDate( relativeDateTime ); if ( convertedRelativeDate == null ) { - // in case the base date time has not at least day precision + // in case the base date/time has not at least day precision return null; } final LocalDate convertedDate = castDate( dateTime ); @@ -114,33 +140,77 @@ public Integer getAge( @Nonnull Object relativeDateTime, @Nullable Object dateTi } @Nullable + @ScriptMethod( description = "Returns the age relative to the current date/time in the specified unit.", + args = { + @ScriptMethodArg( value = "dateTime", description = "The date/time value for which the age should be calculated." ), + @ScriptMethodArg( value = "dateUnit", description = "The unit of the returned age (YEARS, MONTHS, DAYS)." ), + }, + returnDescription = "The age in the specified unit." + ) public Integer getAge( @Nullable Object dateTime, @Nonnull Object dateUnit ) { return getAge( ZonedDateTime.now(), dateTime, dateUnit ); } + @ScriptMethod( description = "Returns if the age relative to the specified date/time in the specified unit is younger than the specified amount.", + args = { + @ScriptMethodArg( value = "relativeDateTime", description = "The date/time value to which the age should be calculated relatively. If the date/time value is today then the age is calcualted for the current date." ), + @ScriptMethodArg( value = "dateTime", description = "The date/time value for which the age up to the relative date/time value should be calculated." ), + @ScriptMethodArg( value = "amount", description = "The maximum age (exclusive)." ), + @ScriptMethodArg( value = "dateUnit", description = "The unit of the returned age (YEARS, MONTHS, DAYS)." ), + }, + returnDescription = "If the age is less than the specified amount." + ) public boolean isYoungerThan( @Nonnull Object relativeDateTime, @Nullable Object dateTime, int amount, @Nonnull Object dateUnit ) { final Integer age = getAge( relativeDateTime, dateTime, dateUnit ); return (age != null) && (age < amount); } + @ScriptMethod( description = "Returns if the age relative to the current date/time in the specified unit is younger than the specified amount.", + args = { + @ScriptMethodArg( value = "dateTime", description = "The date/time value for which the age up to the current date/time value should be calculated." ), + @ScriptMethodArg( value = "amount", description = "The maximum age (exclusive)." ), + @ScriptMethodArg( value = "dateUnit", description = "The unit of the returned age (YEARS, MONTHS, DAYS)." ), + }, + returnDescription = "If the age is less than the specified amount." + ) public boolean isYoungerThan( @Nullable Object dateTime, int amount, @Nonnull Object dateUnit ) { return isYoungerThan( ZonedDateTime.now(), dateTime, amount, dateUnit ); } + @ScriptMethod( description = "Returns if the age relative to the specified date/time in the specified unit is older than the specified amount.", + args = { + @ScriptMethodArg( value = "relativeDateTime", description = "The date/time value to which the age should be calculated relatively. If the date/time value is today then the age is calcualted for the current date." ), + @ScriptMethodArg( value = "dateTime", description = "The date/time value for which the age up to the relative date/time value should be calculated." ), + @ScriptMethodArg( value = "amount", description = "The minimum age (exclusive)." ), + @ScriptMethodArg( value = "dateUnit", description = "The unit of the returned age (YEARS, MONTHS, DAYS)." ), + }, + returnDescription = "If the age is greater than the specified amount." + ) public boolean isOlderThan( @Nonnull Object relativeDateTime, @Nullable Object dateTime, int amount, @Nonnull Object dateUnit ) { final Integer age = getAge( relativeDateTime, dateTime, dateUnit ); return (age != null) && (age > amount); } + @ScriptMethod( description = "Returns if the age relative to the current date/time in the specified unit is older than the specified amount.", + args = { + @ScriptMethodArg( value = "dateTime", description = "The date/time value for which the age up to the current date/time value should be calculated." ), + @ScriptMethodArg( value = "amount", description = "The minimum age (exclusive)." ), + @ScriptMethodArg( value = "dateUnit", description = "The unit of the returned age (YEARS, MONTHS, DAYS)." ), + }, + returnDescription = "If the age is greater than the specified amount." + ) public boolean isOlderThan( @Nullable Object dateTime, int amount, @Nonnull Object dateUnit ) { return isOlderThan( ZonedDateTime.now(), dateTime, amount, dateUnit ); } + @ScriptMethod( description = "Returns if the specified FHIR period is valid now. It is regarded as being valid, if the end has not yet been reached. The begin date/time will not be checked.", + args = @ScriptMethodArg( value = "period", description = "The FHIR period for which it should be checked if the current date/time is included." ), + returnDescription = "Returns if the current date/time is included in the specified period. Returns true if the specified period is null." ) public abstract boolean isValidNow( @Nullable ICompositeType period ); @Nullable diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractFhirClientFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractFhirClientFhirToDhisTransformerUtils.java index 589385fc..1cb14a9b 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractFhirClientFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractFhirClientFhirToDhisTransformerUtils.java @@ -31,7 +31,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.rest.api.CacheControlDirective; import ca.uhn.fhir.rest.client.api.IGenericClient; -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.metadata.model.RemoteSubscriptionResource; import org.dhis2.fhir.adapter.fhir.metadata.model.ScriptVariable; import org.dhis2.fhir.adapter.fhir.metadata.model.SystemCode; @@ -44,6 +43,8 @@ import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionException; import org.dhis2.fhir.adapter.fhir.transform.FhirToDhisTransformerContext; import org.dhis2.fhir.adapter.fhir.transform.TransformerMappingException; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +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.instance.model.api.IIdType; @@ -60,10 +61,17 @@ import java.util.function.Function; import java.util.stream.Collectors; +/** + * FHIR to DHIS2 transformer utility methods for retrieving data from a remote FHIR service. + * + * @author volsch + */ @Scriptable +@ScriptType( value = "FhirClientUtils", var = AbstractFhirClientFhirToDhisTransformerUtils.SCRIPT_ATTR_NAME, + description = "Utilities for retrieving data from a remote FHIR service." ) public abstract class AbstractFhirClientFhirToDhisTransformerUtils extends AbstractFhirToDhisTransformerUtils { - private static final String SCRIPT_ATTR_NAME = "fhirClientUtils"; + public static final String SCRIPT_ATTR_NAME = "fhirClientUtils"; private final FhirContext fhirContext; diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractFhirToDhisTransformerUtils.java index 7c7f1098..a2b82170 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractFhirToDhisTransformerUtils.java @@ -39,6 +39,11 @@ import java.util.HashSet; import java.util.Set; +/** + * Abstract base class for all FHIR to DHIS2 transformer utility classes. + * + * @author volsch + */ public abstract class AbstractFhirToDhisTransformerUtils implements FhirToDhisTransformerUtils { protected static final Set ALL_FHIR_VERSIONS = Collections.unmodifiableSet( new HashSet<>( Arrays.asList( FhirVersion.values() ) ) ); diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractGeoFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractGeoFhirToDhisTransformerUtils.java index 3edd2468..4c1e94ec 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractGeoFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractGeoFhirToDhisTransformerUtils.java @@ -29,26 +29,36 @@ */ import ca.uhn.fhir.model.api.IElement; -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; import org.dhis2.fhir.adapter.fhir.transform.TransformerException; import org.dhis2.fhir.adapter.geo.Location; import org.dhis2.fhir.adapter.geo.StringToLocationConverter; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nonnull; import javax.annotation.Nullable; +/** + * FHIR to DHIS2 transformer utility methods for GEO information handling. + * + * @author volsch + */ @Scriptable +@ScriptType( value = "GeoUtils", var = AbstractGeoFhirToDhisTransformerUtils.SCRIPT_ATTR_NAME, + description = "Utilities for GEO information handling." ) public abstract class AbstractGeoFhirToDhisTransformerUtils extends AbstractFhirToDhisTransformerUtils { + public static final String SCRIPT_ATTR_NAME = "geoUtils"; + protected static final String GEO_LOCATION_URI = "http://hl7.org/fhir/StructureDefinition/geolocation"; protected static final String LATITUDE_URL = "latitude"; protected static final String LONGITUDE_URL = "longitude"; - private static final String SCRIPT_ATTR_NAME = "geoUtils"; - protected AbstractGeoFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) { super( scriptExecutionContext ); @@ -62,6 +72,12 @@ public final String getScriptAttrName() } @Nullable + @ScriptMethod( description = "Creates a location object (type Location) from the specified longitude and latitude.", + args = { + @ScriptMethodArg( value = "longitude", description = "The longitude of the GEO point." ), + @ScriptMethodArg( value = "latitude", description = "The latitude of the GEO point." ), + }, + returnDescription = "The created location object." ) public Location create( @Nullable Number longitude, @Nullable Number latitude ) { if ( (longitude == null) || (latitude == null) ) @@ -71,11 +87,17 @@ public Location create( @Nullable Number longitude, @Nullable Number latitude ) return new Location( longitude.doubleValue(), latitude.doubleValue() ); } + @ScriptMethod( description = "Returns if the specified string representation of coordinates is a location.", + args = @ScriptMethodArg( value = "coordinates", description = "The coordinate string representation that should be checked." ), + returnDescription = "If the specified coordinates represent the string representation of a location." ) public boolean isLocation( @Nullable String coordinates ) { return StringToLocationConverter.isLocation( coordinates ); } @Nullable + @ScriptMethod( description = "Returns the location from the FHIR element address (FHIR extension http://hl7.org/fhir/StructureDefinition/geolocation).", + args = @ScriptMethodArg( value = "element", description = "The FHIR element address from which the location should be returned." ), + returnDescription = "The location (type Location) that is included in the specified element or null if no location is included." ) public abstract Location getLocation( @Nonnull IElement element ) throws TransformerException; } diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractHumanNameFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractHumanNameFhirToDhisTransformerUtils.java index 5a16bc24..70e9584a 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractHumanNameFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractHumanNameFhirToDhisTransformerUtils.java @@ -28,20 +28,30 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.instance.model.api.ICompositeType; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; +/** + * FHIR to DHIS2 transformer utility methods for human names. + * + * @author volsch + */ @Scriptable +@ScriptType( value = "HumanNameUtils", var = AbstractHumanNameFhirToDhisTransformerUtils.SCRIPT_ATTR_NAME, + description = "Utilities to handle FHIR to DHIS2 transformations of human names." ) public abstract class AbstractHumanNameFhirToDhisTransformerUtils extends AbstractFhirToDhisTransformerUtils { - protected static final String DEFAULT_GIVEN_DELIMITER = " "; + public static final String SCRIPT_ATTR_NAME = "humanNameUtils"; - private static final String SCRIPT_ATTR_NAME = "humanNameUtils"; + protected static final String DEFAULT_GIVEN_DELIMITER = " "; protected AbstractHumanNameFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) { @@ -56,10 +66,14 @@ public final String getScriptAttrName() } @Nullable + @ScriptMethod( description = "Return a single given name from the specified FHIR human name. If the human name contains multiple given names these are separated by space characters.", + args = @ScriptMethodArg( value = "humanName", description = "The human name from which the single given name should be extracted." ), + returnDescription = "The extracted single given name." ) public abstract String getSingleGiven( @Nullable ICompositeType humanName ); - public abstract boolean hasPrimaryName( @Nonnull List names ); - @Nullable + @ScriptMethod( description = "Extracts the name of the list of names that seems to be the most appropriate name.", + args = @ScriptMethodArg( value = "names", description = "The list of names from which one name should be extracted." ), + returnDescription = "The extracted primary name." ) public abstract ICompositeType getPrimaryName( @Nonnull List names ); } diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractIdentifierFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractIdentifierFhirToDhisTransformerUtils.java index 5db76f67..7247057a 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractIdentifierFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractIdentifierFhirToDhisTransformerUtils.java @@ -28,7 +28,6 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.metadata.model.FhirResourceType; import org.dhis2.fhir.adapter.fhir.metadata.model.ScriptVariable; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; @@ -38,6 +37,10 @@ import org.dhis2.fhir.adapter.fhir.transform.TransformerMappingException; import org.dhis2.fhir.adapter.fhir.transform.impl.TransformerScriptException; import org.dhis2.fhir.adapter.fhir.transform.model.ResourceSystem; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.instance.model.api.IBaseReference; import org.hl7.fhir.instance.model.api.IDomainResource; import org.springframework.util.ReflectionUtils; @@ -49,10 +52,17 @@ import java.util.Map; import java.util.Objects; +/** + * FHIR to DHIS2 transformer utility methods for FHIR identifiers. + * + * @author volsch + */ @Scriptable +@ScriptType( value = "IdentifierUtils", var = AbstractIdentifierFhirToDhisTransformerUtils.SCRIPT_ATTR_NAME, + description = "Utilities to handle FHIR to DHIS2 transformations of FHIR identifiers." ) public abstract class AbstractIdentifierFhirToDhisTransformerUtils extends AbstractFhirToDhisTransformerUtils { - private static final String SCRIPT_ATTR_NAME = "identifierUtils"; + public static final String SCRIPT_ATTR_NAME = "identifierUtils"; private volatile Map, Method> identifierMethods = new HashMap<>(); @@ -71,11 +81,15 @@ public final String getScriptAttrName() return SCRIPT_ATTR_NAME; } - @Nullable - protected abstract String getIdentifierValue( @Nonnull IDomainResource domainResource, @Nonnull Method identifierMethod, @Nullable String system ); - @Nullable @ScriptExecutionRequired + @ScriptMethod( description = "Returns the business identifier from the specified referenced FHIR resource with the specified FHIR resource type. If the resource type does not match null is returned. " + + "The system URI of the corresponding remote subscription system of the current transformation context is used (e.g. the system URI of a Patient of the remote subscription from which the resource has been retrieved).", + args = { + @ScriptMethodArg( value = "reference", description = "The FHIR reference of a domain resource from which the identifier should be extracted." ), + @ScriptMethodArg( value = "fhirResourceType", description = "The FHIR resource type (upper case with underscores, e.g. RELATED_PERSON) of the specified domain resource." ) + }, + returnDescription = "The corresponding business identifier." ) public String getReferenceIdentifier( @Nullable IBaseReference reference, @Nonnull Object fhirResourceType ) throws TransformerException { if ( (reference == null) || reference.isEmpty() ) @@ -90,8 +104,14 @@ public String getReferenceIdentifier( @Nullable IBaseReference reference, @Nonnu return null; } - @Nullable + @ScriptMethod( description = "Returns the business identifier with the specified system URI from the referenced FHIR resource with the specified FHIR resource type. If the resource type does not match null is returned.", + args = { + @ScriptMethodArg( value = "reference", description = "The FHIR reference of a domain resource from which the identifier should be extracted." ), + @ScriptMethodArg( value = "fhirResourceType", description = "The FHIR resource type (upper case with underscores, e.g. RELATED_PERSON) of the specified domain resource." ), + @ScriptMethodArg( value = "system", description = "The system URI for which the identifier is returned." ) + }, + returnDescription = "The corresponding business identifier." ) public String getReferenceIdentifier( @Nullable IBaseReference reference, @Nonnull Object fhirResourceType, @Nullable String system ) throws TransformerException { if ( (reference == null) || reference.isEmpty() ) @@ -108,6 +128,13 @@ public String getReferenceIdentifier( @Nullable IBaseReference reference, @Nonnu @Nullable @ScriptExecutionRequired + @ScriptMethod( description = "Returns the business identifier from the specified domain resource with the specified FHIR resource type. If the resource type does not match null is returned. " + + "The system URI of the corresponding remote subscription system of the current transformation context is used (e.g. the system URI of a Patient of the remote subscription from which the resource has been retrieved).", + args = { + @ScriptMethodArg( value = "resource", description = "The FHIR domain resource from which the identifier should be extracted." ), + @ScriptMethodArg( value = "fhirResourceType", description = "The FHIR resource type (upper case with underscores, e.g. RELATED_PERSON) of the specified domain resource." ) + }, + returnDescription = "The corresponding business identifier." ) public String getResourceIdentifier( @Nullable IDomainResource resource, @Nonnull Object fhirResourceType ) throws TransformerException { if ( resource == null ) @@ -130,27 +157,37 @@ public String getResourceIdentifier( @Nullable IDomainResource resource, @Nonnul } @Nullable - public String getResourceIdentifier( @Nullable IDomainResource domainResource, @Nonnull Object fhirResourceType, @Nullable String system ) throws TransformerException + @ScriptMethod( description = "Returns the business identifier with the specified system URI from the specified domain resource with the specified FHIR resource type. If the resource type does not match null is returned.", + args = { + @ScriptMethodArg( value = "resource", description = "The FHIR domain resource from which the identifier should be extracted." ), + @ScriptMethodArg( value = "fhirResourceType", description = "The FHIR resource type (upper case with underscores, e.g. RELATED_PERSON) of the specified domain resource." ), + @ScriptMethodArg( value = "system", description = "The system URI for which the identifier is returned." ) + }, + returnDescription = "The corresponding business identifier." ) + public String getResourceIdentifier( @Nullable IDomainResource resource, @Nonnull Object fhirResourceType, @Nullable String system ) throws TransformerException { - if ( domainResource == null ) + if ( resource == null ) { throw new TransformerMappingException( "Cannot get identifier of undefined domain resource." ); } - if ( !Objects.equals( String.valueOf( FhirResourceType.getByResource( domainResource ) ), String.valueOf( fhirResourceType ) ) ) + if ( !Objects.equals( String.valueOf( FhirResourceType.getByResource( resource ) ), String.valueOf( fhirResourceType ) ) ) { return null; } - final Method method = getIdentifierMethod( domainResource ); + final Method method = getIdentifierMethod( resource ); if ( method != null ) { - return getIdentifierValue( domainResource, method, system ); + return getIdentifierValue( resource, method, system ); } return null; } + @Nullable + protected abstract String getIdentifierValue( @Nonnull IDomainResource domainResource, @Nonnull Method identifierMethod, @Nullable String system ); + @Nullable private Method getIdentifierMethod( @Nonnull IDomainResource domainResource ) { diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractImmunizationFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractImmunizationFhirToDhisTransformerUtils.java index 9426c4e3..e5052ae5 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractImmunizationFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractImmunizationFhirToDhisTransformerUtils.java @@ -28,9 +28,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; import org.dhis2.fhir.adapter.fhir.transform.TransformerException; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.instance.model.api.IDomainResource; import javax.annotation.Nonnull; diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractObservationFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractObservationFhirToDhisTransformerUtils.java index 685511c5..825faa01 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractObservationFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractObservationFhirToDhisTransformerUtils.java @@ -28,8 +28,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +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; diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractOrganizationFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractOrganizationFhirToDhisTransformerUtils.java index fdeb1529..2a350dd4 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractOrganizationFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractOrganizationFhirToDhisTransformerUtils.java @@ -47,6 +47,10 @@ import org.dhis2.fhir.adapter.fhir.transform.TransformerDataException; import org.dhis2.fhir.adapter.fhir.transform.TransformerMappingException; import org.dhis2.fhir.adapter.fhir.transform.model.ResourceSystem; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseReference; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -62,13 +66,16 @@ import java.util.UUID; /** - * Transformer utilities for organization. + * Transformer utilities for FHIR organizations. * * @author volsch */ +@Scriptable +@ScriptType( value = "OrganizationUtils", var = AbstractOrganizationFhirToDhisTransformerUtils.SCRIPT_ATTR_NAME, + description = "Utilities to handle FHIR to DHIS2 transformations of FHIR organizations." ) public abstract class AbstractOrganizationFhirToDhisTransformerUtils extends AbstractFhirToDhisTransformerUtils { - private static final String SCRIPT_ATTR_NAME = "organizationUtils"; + public static final String SCRIPT_ATTR_NAME = "organizationUtils"; private final Logger logger = LoggerFactory.getLogger( getClass() ); @@ -100,23 +107,23 @@ public String getScriptAttrName() return SCRIPT_ATTR_NAME; } - @ScriptExecutionRequired + @ScriptMethod( description = "Checks if the specified DHIS2 organization unit code exists on DHIS2.", + args = @ScriptMethodArg( value = "code", description = "The DHIS2 organization unit code that should be checked." ), + returnDescription = "If the specified DHIS2 organization unit code exists." ) public boolean exists( @Nullable String code ) { if ( code == null ) { return false; } - - final FhirToDhisTransformerContext context = getScriptVariable( ScriptVariable.CONTEXT.getVariableName(), FhirToDhisTransformerContext.class ); - final ResourceSystem resourceSystem = context.getFhirRequest().getOptionalResourceSystem( FhirResourceType.ORGANIZATION ) - .orElseThrow( () -> new TransformerMappingException( "No system has been defined for resource type " + FhirResourceType.ORGANIZATION + "." ) ); - return organisationUnitService.findOneByReference( new Reference( code, ReferenceType.CODE ) ).isPresent(); } - @ScriptExecutionRequired @Nullable + @ScriptExecutionRequired + @ScriptMethod( description = "Checks if the specified DHIS2 organization unit code exists on DHIS2 with the code prefix that is defined for organizations of the remote subscription of the current transformation context.", + args = @ScriptMethodArg( value = "code", description = "The DHIS2 organization unit code (without prefix) that should be checked." ), + returnDescription = "The DHIS2 organization unit code (includin prefix, as it exists on DHIS2) or null if it does not exist." ) public String existsWithPrefix( @Nullable String code ) { if ( code == null ) @@ -137,6 +144,9 @@ public String existsWithPrefix( @Nullable String code ) } @Nullable + @ScriptMethod( description = "Return a list with all FHIR organizations from the specified organization reference until the root FHIR organization. The first list item is the organization resource that is referenced by the specified reference.", + args = @ScriptMethodArg( value = "childReference", description = "The reference to a FHIR organization resource for which all parents should be returned (including the specified child)." ), + returnDescription = "List of FHIR resources in the hierarchy up to the root organization." ) public List findHierarchy( @Nullable IBaseReference childReference ) { return findHierarchy( childReference, new HashSet<>() ); diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractPatientFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractPatientFhirToDhisTransformerUtils.java index d9d23dac..8c4c110a 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractPatientFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractPatientFhirToDhisTransformerUtils.java @@ -28,20 +28,30 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.instance.model.api.ICompositeType; import org.hl7.fhir.instance.model.api.IDomainResource; import javax.annotation.Nonnull; import javax.annotation.Nullable; +/** + * Transformer utilities for FHIR patients. + * + * @author volsch + */ @Scriptable +@ScriptType( value = "PatientUtils", var = AbstractPatientFhirToDhisTransformerUtils.SCRIPT_ATTR_NAME, + description = "Utilities to handle FHIR to DHIS2 transformations of FHIR patients." ) public abstract class AbstractPatientFhirToDhisTransformerUtils extends AbstractFhirToDhisTransformerUtils { - protected static final String BIRTH_PLACE_URI = "http://hl7.org/fhir/StructureDefinition/birthPlace"; + public static final String SCRIPT_ATTR_NAME = "patientUtils"; - private static final String SCRIPT_ATTR_NAME = "patientUtils"; + protected static final String BIRTH_PLACE_URI = "http://hl7.org/fhir/StructureDefinition/birthPlace"; protected AbstractPatientFhirToDhisTransformerUtils( @Nonnull ScriptExecutionContext scriptExecutionContext ) { @@ -56,5 +66,9 @@ public final String getScriptAttrName() } @Nullable + @ScriptMethod( description = "Returns the FHIR address that contains the birth place. The FHIR extension http://hl7.org/fhir/StructureDefinition/birthPlace is used to extract the address.", + args = @ScriptMethodArg( value = "patient", description = "The patient resource from which the birth place address should be extracted." ), + returnDescription = "The extracted birth place address." + ) public abstract ICompositeType getBirthPlaceAddress( @Nullable IDomainResource patient ); } diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractVitalSignFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractVitalSignFhirToDhisTransformerUtils.java index 06f8dac6..8f59844a 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractVitalSignFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/AbstractVitalSignFhirToDhisTransformerUtils.java @@ -28,9 +28,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; import org.dhis2.fhir.adapter.fhir.transform.TransformerDataException; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.instance.model.api.ICompositeType; import javax.annotation.Nonnull; diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/ReferenceFhirToDhisTransformerUtils.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/ReferenceFhirToDhisTransformerUtils.java index 5fba72ed..e69f078b 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/ReferenceFhirToDhisTransformerUtils.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/impl/util/ReferenceFhirToDhisTransformerUtils.java @@ -29,7 +29,6 @@ */ import ca.uhn.fhir.context.FhirContext; -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.metadata.model.FhirResourceType; import org.dhis2.fhir.adapter.fhir.metadata.model.RemoteSubscription; import org.dhis2.fhir.adapter.fhir.metadata.model.RemoteSubscriptionResource; @@ -43,6 +42,10 @@ import org.dhis2.fhir.adapter.fhir.transform.TransformerDataException; import org.dhis2.fhir.adapter.fhir.transform.TransformerMappingException; import org.dhis2.fhir.adapter.fhir.transform.impl.TransformerScriptException; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import org.hl7.fhir.instance.model.api.IBaseReference; import org.hl7.fhir.instance.model.api.IBaseResource; import org.slf4j.Logger; @@ -62,9 +65,11 @@ */ @Component @Scriptable +@ScriptType( value = "ReferenceUtils", var = ReferenceFhirToDhisTransformerUtils.SCRIPT_ATTR_NAME, + description = "Utilities to resolve FHIR Reference to FHIR Resources when handling FHIR to DHIS2 transformations." ) public class ReferenceFhirToDhisTransformerUtils extends AbstractFhirToDhisTransformerUtils { - private static final String SCRIPT_ATTR_NAME = "referenceUtils"; + public static final String SCRIPT_ATTR_NAME = "referenceUtils"; private final Logger logger = LoggerFactory.getLogger( getClass() ); @@ -106,12 +111,27 @@ public void initReference( @Nullable IBaseReference reference, @Nullable Object } @Nullable + @ScriptMethod( description = "Returns the FHIR resource with the specified resource type for the specified FHIR reference. The returned FHIR resource may be a cached version of the resource and may not contain the latest data.", + args = { + @ScriptMethodArg( value = "reference", description = "The FHIR reference for which the resource should be returned." ), + @ScriptMethodArg( value = "resourceType", description = "The FHIR resource type of the resource (upper case with under scores, e.g. RELATED_PERSON). If this is not specified the resource type must be included in the reference. " + + "If this is specified and the resource type is also included in the reference, then both must match." ) + }, + returnDescription = "The FHIR resource for the specified reference." ) public IBaseResource getResource( @Nullable IBaseReference reference, @Nullable Object resourceType ) { return getResource( reference, resourceType, false ); } @Nullable + @ScriptMethod( description = "Returns the FHIR resource with the specified resource type for the specified FHIR reference.", + args = { + @ScriptMethodArg( value = "reference", description = "The FHIR reference for which the resource should be returned." ), + @ScriptMethodArg( value = "resourceType", description = "The FHIR resource type of the resource (upper case with under scores, e.g. RELATED_PERSON). If this is not specified the resource type must be included in the reference. " + + "If this is specified and the resource type is also included in the reference, then both must match." ), + @ScriptMethodArg( value = "refreshed", description = "Specifies if the latest version of the resource should be returned. If this is set to false, a cached version may be returned." ) + }, + returnDescription = "The FHIR resource for the specified reference." ) public IBaseResource getResource( @Nullable IBaseReference reference, @Nullable Object resourceType, boolean refreshed ) { if ( reference == null ) diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/model/FhirRequest.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/model/FhirRequest.java index cbae1478..c19aa6bc 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/model/FhirRequest.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/model/FhirRequest.java @@ -28,9 +28,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.metadata.model.FhirResourceType; import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.scriptable.ScriptMethod; +import org.dhis2.fhir.adapter.scriptable.ScriptType; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -39,11 +41,13 @@ import java.util.UUID; @Scriptable +@ScriptType( value = "FhirRequest", description = "The current FHIR request that caused the execution of the transformation." ) public interface FhirRequest { @Nullable FhirRequestMethod getRequestMethod(); + @ScriptMethod( description = "Returns the processed FHIR resource type as Java enumeration (e.g. RELATED_PERSON as enum constant)." ) FhirResourceType getResourceType(); @Nullable @@ -53,13 +57,19 @@ public interface FhirRequest String getResourceVersionId(); @Nullable + @ScriptMethod( description = "Returns the timestamp when the processed FHIR resource has been updated the last time." ) ZonedDateTime getLastUpdated(); @Nonnull + @ScriptMethod( description = "Returns the FHIR version of the processed FHIR resource as Java enumeration (e.g. DSTU3 as enum constant)." ) FhirVersion getVersion(); boolean isRemoteSubscription(); + @Nullable + @ScriptMethod( description = "Returns the code of the remote subscription that caused the execution of the current transformation." ) + String getRemoteSubscriptionCode(); + @Nullable UUID getRemoteSubscriptionResourceId(); diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/model/ImmutableFhirRequest.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/model/ImmutableFhirRequest.java index 10c8df7e..bad823e6 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/model/ImmutableFhirRequest.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/model/ImmutableFhirRequest.java @@ -28,9 +28,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.dhis2.fhir.adapter.Scriptable; import org.dhis2.fhir.adapter.fhir.metadata.model.FhirResourceType; import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.scriptable.Scriptable; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -106,6 +106,13 @@ public boolean isRemoteSubscription() return delegate.isRemoteSubscription(); } + @Nullable + @Override + public String getRemoteSubscriptionCode() + { + return delegate.getRemoteSubscriptionCode(); + } + @Override @Nullable public UUID getRemoteSubscriptionResourceId() diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/model/WritableFhirRequest.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/model/WritableFhirRequest.java index ad925664..f69a31a1 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/model/WritableFhirRequest.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/model/WritableFhirRequest.java @@ -60,6 +60,8 @@ public class WritableFhirRequest implements FhirRequest, Serializable private String dhisUsername; + private String remoteSubscriptionCode; + private UUID remoteSubscriptionResourceId; private Map resourceSystemsByType; @@ -176,6 +178,18 @@ public void setRemoteSubscriptionResourceId( UUID remoteSubscriptionResourceId ) this.remoteSubscriptionResourceId = remoteSubscriptionResourceId; } + @Nullable + @Override + public String getRemoteSubscriptionCode() + { + return remoteSubscriptionCode; + } + + public void setRemoteSubscriptionCode( String remoteSubscriptionCode ) + { + this.remoteSubscriptionCode = remoteSubscriptionCode; + } + public Map getResourceSystemsByType() { return resourceSystemsByType; diff --git a/fhir/src/main/resources/db/migration/production/V1.0.0.0_0_0__Initial.sql b/fhir/src/main/resources/db/migration/production/V1.0.0.0_0_0__Initial.sql index 91ec88f9..09093617 100644 --- a/fhir/src/main/resources/db/migration/production/V1.0.0.0_0_0__Initial.sql +++ b/fhir/src/main/resources/db/migration/production/V1.0.0.0_0_0__Initial.sql @@ -1995,7 +1995,7 @@ VALUES ('bee0e77c-d2a5-4950-ae2e-2e399c1c3629', 0, '05fb37c2-7e68-45c0-bfe7-8699 INSERT INTO fhir_script_source (id, version, script_id, source_text, source_type) VALUES ('0cb05413-c78a-4b27-97fc-a73c3cb9c430', 0, '05fb37c2-7e68-45c0-bfe7-86999492e202', 'function getMatchingRelatedPerson(relatedPersons, relationshipTypeCodes, preferredGender) { - var groupedSystemCodeValues = codeUtils.getSystemCodeValuesByCodes(relationshipTypeCodes); + var groupedSystemCodeValues = codeUtils.getSystemCodeValuesByMappingCodes(relationshipTypeCodes); for (var j = 0; j < relationshipTypeCodes.length; j++ ) { var systemCodeValues = groupedSystemCodeValues[relationshipTypeCodes[j]]; diff --git a/fhir/src/test/java/org/dhis2/fhir/adapter/fhir/transform/impl/FhirToDhisTransformerContextImplTest.java b/fhir/src/test/java/org/dhis2/fhir/adapter/fhir/transform/impl/FhirToDhisTransformerContextImplTest.java index 71568d81..b9dd308f 100644 --- a/fhir/src/test/java/org/dhis2/fhir/adapter/fhir/transform/impl/FhirToDhisTransformerContextImplTest.java +++ b/fhir/src/test/java/org/dhis2/fhir/adapter/fhir/transform/impl/FhirToDhisTransformerContextImplTest.java @@ -30,7 +30,6 @@ import org.dhis2.fhir.adapter.dhis.model.Reference; import org.dhis2.fhir.adapter.dhis.model.ReferenceType; -import org.dhis2.fhir.adapter.fhir.transform.TransformerDataException; import org.dhis2.fhir.adapter.fhir.transform.model.FhirRequest; import org.dhis2.fhir.adapter.fhir.transform.model.ImmutableFhirRequest; import org.junit.Assert; @@ -99,29 +98,4 @@ public void isCreationDisabled() { Assert.assertTrue( context.isCreationDisabled() ); } - - @Test - public void failIfNullNotNull() - { - context.failIfNull( "This is a test!!!", 10 ); - } - - @Test( expected = TransformerDataException.class ) - public void failIfNull() - { - try - { - context.failIfNull( "This is a test!!!", null ); - } - catch ( TransformerDataException e ) - { - Assert.assertEquals( "This is a test!!!", e.getMessage() ); - throw e; - } - } - - @Test - public void fail() - { - } } \ No newline at end of file diff --git a/pom.xml b/pom.xml index 18acf4a4..f265a6de 100644 --- a/pom.xml +++ b/pom.xml @@ -144,6 +144,13 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + -parameters + + org.apache.maven.plugins maven-surefire-plugin @@ -188,6 +195,11 @@ commons-io 2.6 + + org.apache.commons + commons-text + 1.6 + org.apache.httpcomponents httpclient