diff --git a/README.md b/README.md index d82ee7f1..173ec11b 100644 --- a/README.md +++ b/README.md @@ -128,13 +128,12 @@ For the initial setup of the Adapter a simple user interface is provided. To acc java -jar dhis2-fhir-adapter.war --adapter-setup=true -With the default configuration the initial setup user interface can be accessed in any web browser by using http://localhost:8081/setup. The web browser will ask for a username and password of a DHIS2 user that has privilege F_SYSTEM_SETTING. After +With the default configuration the initial setup user interface can be accessed in any web browser by using `http://localhost:8081/setup`. The web browser will ask for a username and password of a DHIS2 user that has privilege F_SYSTEM_SETTING. After successful authentication a setup form will be displayed with further instructions and examples. The initial setup can be made once only and the initial setup form will not be accessible anymore. ### 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. + 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. The FHIR resources are exposed to JavaScript by [HAPI FHIR 3.6.0](http://hapifhir.io/) objects. - \ No newline at end of file + then the guide is available at `http://localhost:8081/scripts/to-dhis2-all-mapping.js`. The FHIR resources are exposed to JavaScript by [HAPI FHIR 3.6.0](http://hapifhir.io/) objects. 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 d216a951..e85707cd 100644 --- a/app/src/main/java/org/dhis2/fhir/adapter/WebSecurityConfig.java +++ b/app/src/main/java/org/dhis2/fhir/adapter/WebSecurityConfig.java @@ -83,7 +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.GET, "/scripts/**" ).permitAll() .antMatchers( HttpMethod.OPTIONS, "/api/**" ).permitAll() .antMatchers( "/actuator/**" ).hasRole( AdapterAuthorities.ADMINISTRATION_AUTHORITY ) .anyRequest().authenticated() diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/converter/AbstractAdministrativeGenderToStringConverter.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/converter/AbstractAdministrativeGenderToStringConverter.java index 63519e08..10dd8c6f 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/converter/AbstractAdministrativeGenderToStringConverter.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/converter/AbstractAdministrativeGenderToStringConverter.java @@ -56,10 +56,10 @@ public String doConvert( @Nonnull A source ) throws ConversionException switch ( source.name() ) { case "FEMALE": - return constantResolver.getByCode( GENDER_FEMALE_CONSTANT_CODE ) + return constantResolver.findOneByCode( GENDER_FEMALE_CONSTANT_CODE ) .orElseThrow( () -> new ConversionException( "No constant with code " + GENDER_FEMALE_CONSTANT_CODE + " has been defined." ) ).getValue(); case "MALE": - return constantResolver.getByCode( GENDER_MALE_CONSTANT_CODE ) + return constantResolver.findOneByCode( GENDER_MALE_CONSTANT_CODE ) .orElseThrow( () -> new ConversionException( "No constant with code " + GENDER_MALE_CONSTANT_CODE + " has been defined." ) ).getValue(); case "NULL": case "OTHER": diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/ConstantResolver.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/ConstantResolver.java index 15673b22..785e8260 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/ConstantResolver.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/ConstantResolver.java @@ -28,6 +28,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import org.springframework.data.rest.core.annotation.RestResource; + import javax.annotation.Nonnull; import java.util.Optional; @@ -44,6 +46,7 @@ public interface ConstantResolver * @param code the code of the constant that should be resolved. * @return the constant with the specified code. */ + @RestResource( exported = false ) @Nonnull - Optional getByCode( @Nonnull String code ); + Optional findOneByCode( @Nonnull String code ); } \ No newline at end of file diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/Script.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/Script.java index ba254945..55a14561 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/Script.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/Script.java @@ -29,7 +29,6 @@ */ import com.fasterxml.jackson.annotation.JsonFilter; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.dhis2.fhir.adapter.fhir.metadata.model.jackson.ScriptVariablePersistentSortedSetConverter; import org.dhis2.fhir.adapter.jackson.ToManyPropertyFilter; @@ -43,7 +42,6 @@ import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; -import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.OrderBy; @@ -204,7 +202,7 @@ public void setArguments( List scriptVariables ) } @SuppressWarnings( "JpaAttributeTypeInspection" ) - @ElementCollection( fetch = FetchType.EAGER ) + @ElementCollection @CollectionTable( name = "fhir_script_variable", joinColumns = @JoinColumn( name = "script_id" ) ) @Column( name = "variable" ) @Enumerated( EnumType.STRING ) @@ -220,9 +218,8 @@ public void setVariables( SortedSet variables ) this.variables = variables; } - @OneToMany( mappedBy = "script", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.EAGER ) + @OneToMany( mappedBy = "script", orphanRemoval = true, cascade = CascadeType.ALL ) @OrderBy( "id" ) - @JsonIgnore public List getSources() { return sources; diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/SubscriptionFhirEndpoint.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/SubscriptionFhirEndpoint.java index 1f1f76c9..4ee26b3c 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/SubscriptionFhirEndpoint.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/SubscriptionFhirEndpoint.java @@ -37,7 +37,6 @@ import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Embeddable; -import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.OrderBy; import javax.validation.Valid; @@ -83,7 +82,7 @@ public void setBaseUrl( String baseUrl ) } @SuppressWarnings( "JpaAttributeTypeInspection" ) - @ElementCollection( fetch = FetchType.EAGER ) + @ElementCollection @CollectionTable( name = "fhir_remote_subscription_header", joinColumns = @JoinColumn( name = "remote_subscription_id" ) ) @OrderBy( "name,value" ) @JsonSerialize( converter = PersistentBagConverter.class ) diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/CustomExecutableScriptRepository.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/CustomExecutableScriptRepository.java index 52f96431..83a94072 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/CustomExecutableScriptRepository.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/CustomExecutableScriptRepository.java @@ -32,6 +32,7 @@ import org.dhis2.fhir.adapter.fhir.metadata.model.ExecutableScriptInfo; import org.dhis2.fhir.adapter.fhir.model.FhirVersion; import org.springframework.data.rest.core.annotation.RestResource; +import org.springframework.security.access.prepost.PreAuthorize; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -46,5 +47,6 @@ public interface CustomExecutableScriptRepository { @RestResource( exported = false ) @Nonnull + @PreAuthorize( "permitAll()" ) Optional findInfo( @Nullable ExecutableScript executableScript, @Nonnull FhirVersion fhirVersion ); } diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/CustomRemoteSubscriptionResourceRepository.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/CustomRemoteSubscriptionResourceRepository.java new file mode 100644 index 00000000..f2a3e010 --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/CustomRemoteSubscriptionResourceRepository.java @@ -0,0 +1,50 @@ +package org.dhis2.fhir.adapter.fhir.metadata.repository; + +/* + * 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.fhir.metadata.model.RemoteSubscriptionResource; +import org.springframework.data.rest.core.annotation.RestResource; +import org.springframework.security.access.prepost.PreAuthorize; + +import javax.annotation.Nonnull; +import java.util.Optional; +import java.util.UUID; + +/** + * Custom repository for {@link RemoteSubscriptionResource}. + * + * @author volsch + */ +public interface CustomRemoteSubscriptionResourceRepository +{ + @RestResource( exported = false ) + @Nonnull + @PreAuthorize( "permitAll()" ) + Optional findByIdCached( @Nonnull UUID id ); +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/RemoteSubscriptionResourceRepository.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/RemoteSubscriptionResourceRepository.java index 85b706a8..5c92d27b 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/RemoteSubscriptionResourceRepository.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/RemoteSubscriptionResourceRepository.java @@ -56,15 +56,8 @@ @CacheConfig( cacheManager = "metadataCacheManager", cacheNames = "remoteSubscriptionResource" ) @RepositoryRestResource @PreAuthorize( "hasRole('ADMINISTRATION')" ) -public interface RemoteSubscriptionResourceRepository extends JpaRepository, QuerydslPredicateExecutor +public interface RemoteSubscriptionResourceRepository extends JpaRepository, QuerydslPredicateExecutor, CustomRemoteSubscriptionResourceRepository { - @RestResource( exported = false ) - @Query( "SELECT r FROM #{#entityName} r JOIN FETCH r.remoteSubscription s WHERE r.id=:id" ) - @Nonnull - @Cacheable( key = "#a0" ) - @PreAuthorize( "permitAll()" ) - Optional findByIdCached( @Param( "id" ) @Nonnull UUID id ); - @RestResource( exported = false ) @Query( "SELECT r FROM #{#entityName} r JOIN FETCH r.remoteSubscription s WHERE s=:subscription AND r.fhirResourceType=:fhirResourceType ORDER BY r.id" ) @Nonnull diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/impl/CustomExecutableScriptRepositoryImpl.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/impl/CustomExecutableScriptRepositoryImpl.java index 517eed62..cff93ecb 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/impl/CustomExecutableScriptRepositoryImpl.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/impl/CustomExecutableScriptRepositoryImpl.java @@ -81,6 +81,7 @@ public Optional findInfo( @Nullable ExecutableScript execu } Hibernate.initialize( es.getOverrideArguments() ); Hibernate.initialize( es.getScript().getArguments() ); + Hibernate.initialize( es.getScript().getVariables() ); final ScriptSource scriptSource = entityManager.createQuery( "SELECT ss FROM ScriptSource ss WHERE ss.script=:script AND :fhirVersion MEMBER OF ss.fhirVersions", ScriptSource.class ) .setParameter( "script", es.getScript() ).setParameter( "fhirVersion", fhirVersion ).getResultList().stream().findFirst().orElse( null ); diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/impl/CustomRemoteSubscriptionResourceRepositoryImpl.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/impl/CustomRemoteSubscriptionResourceRepositoryImpl.java new file mode 100644 index 00000000..ad41f5c6 --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/impl/CustomRemoteSubscriptionResourceRepositoryImpl.java @@ -0,0 +1,73 @@ +package org.dhis2.fhir.adapter.fhir.metadata.repository.impl; + +/* + * 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.fhir.metadata.model.RemoteSubscriptionResource; +import org.dhis2.fhir.adapter.fhir.metadata.repository.CustomRemoteSubscriptionResourceRepository; +import org.hibernate.Hibernate; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Nonnull; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.util.Optional; +import java.util.UUID; + +/** + * Implementation of {@link CustomRemoteSubscriptionResourceRepository}. + * + * @author volsch + */ +public class CustomRemoteSubscriptionResourceRepositoryImpl implements CustomRemoteSubscriptionResourceRepository +{ + @PersistenceContext + private EntityManager entityManager; + + public CustomRemoteSubscriptionResourceRepositoryImpl( @Nonnull EntityManager entityManager ) + { + this.entityManager = entityManager; + } + + @Nonnull + @Override + @Cacheable( key = "#a0", cacheManager = "metadataCacheManager", cacheNames = "remoteSubscriptionResource" ) + @Transactional( readOnly = true ) + public Optional findByIdCached( @Nonnull UUID id ) + { + final RemoteSubscriptionResource rsr = entityManager.find( RemoteSubscriptionResource.class, id ); + if ( rsr == null ) + { + return Optional.empty(); + } + + Hibernate.initialize( rsr.getRemoteSubscription().getFhirEndpoint().getHeaders() ); + return Optional.of( rsr ); + } +} 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 2a350dd4..c21ac07a 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 @@ -202,7 +202,7 @@ protected List findHierarchy( @Nullable IBaseReference { throw new TransformerMappingException( "FHIR client cannot be created without having a remote request." ); } - final RemoteSubscriptionResource subscriptionResource = subscriptionResourceRepository.findById( resourceId ) + final RemoteSubscriptionResource subscriptionResource = subscriptionResourceRepository.findByIdCached( resourceId ) .orElseThrow( () -> new TransformerMappingException( "Could not find remote subscription resource with ID " + resourceId ) ); final FhirContext fhirContext = remoteFhirRepository.findFhirContext( context.getFhirRequest().getVersion() ) 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 e69f078b..657711d9 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 @@ -204,7 +204,7 @@ public IBaseResource getResource( @Nullable IBaseReference reference, @Nullable { throw new TransformerMappingException( "FHIR client cannot be created without having a remote request." ); } - final RemoteSubscriptionResource subscriptionResource = subscriptionResourceRepository.findById( resourceId ) + final RemoteSubscriptionResource subscriptionResource = subscriptionResourceRepository.findByIdCached( resourceId ) .orElseThrow( () -> new TransformerMappingException( "Could not find remote subscription resource with ID " + resourceId ) ); final FhirContext fhirContext = remoteFhirRepository.findFhirContext( context.getFhirRequest().getVersion() )