Skip to content

Commit

Permalink
Begin of support for remote synchronization
Browse files Browse the repository at this point in the history
(e.g. OpenMRS Sync2).
  • Loading branch information
volsch committed Jan 30, 2019
1 parent 8da4103 commit b8ed06e
Show file tree
Hide file tree
Showing 20 changed files with 694 additions and 108 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.dhis2.fhir.adapter;

/*
* Copyright (c) 2004-2018, University of Oslo
* Copyright (c) 2004-2019, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -69,6 +69,10 @@ protected void configure( @Nonnull HttpSecurity http ) throws Exception
.authorizeRequests()
.antMatchers( HttpMethod.PUT, "/remote-fhir-rest-hook/**" ).permitAll()
.antMatchers( HttpMethod.POST, "/remote-fhir-rest-hook/**" ).permitAll()
.antMatchers( HttpMethod.PUT, "/remote-fhir-sync/**" ).permitAll()
.antMatchers( HttpMethod.POST, "/remote-fhir-sync/**" ).permitAll()
.antMatchers( HttpMethod.DELETE, "/remote-fhir-sync/**" ).permitAll()
.antMatchers( HttpMethod.GET, "/remote-fhir-sync/**" ).permitAll()
.antMatchers( HttpMethod.GET, "/favicon.ico" ).permitAll()
.antMatchers( HttpMethod.GET, "/actuator/health" ).permitAll()
.antMatchers( HttpMethod.GET, "/actuator/info" ).permitAll()
Expand Down
84 changes: 84 additions & 0 deletions common/src/main/java/org/dhis2/fhir/adapter/util/NameUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.dhis2.fhir.adapter.util;

/*
* Copyright (c) 2004-2019, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* Neither the name of the HISP project nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import com.google.common.base.CaseFormat;
import org.apache.commons.lang.StringUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/**
* Name utilities for converting to enum constants and class names.
*/
public abstract class NameUtils
{
@Nullable
public static String toClassName( @Nullable Object value )
{
final String stringValue = toEnumName( value );
if ( stringValue == null )
{
return null;
}
return CaseFormat.UPPER_UNDERSCORE.to( CaseFormat.UPPER_CAMEL, stringValue );
}

@Nonnull
public static <T extends Enum<T>> Enum<T> getEnumValue( @Nonnull Class<T> enumClass, @Nullable Object value ) throws IllegalArgumentException
{
final String stringValue = toEnumName( value );
if ( stringValue == null )
{
throw new IllegalArgumentException( "Null enum values are not allowed" );
}
return Enum.valueOf( enumClass, stringValue );
}

@Nullable
public static String toEnumName( @Nullable Object value )
{
if ( value == null )
{
return null;
}
final String stringValue = value.toString();
if ( stringValue == null )
{
return null;
}
if ( stringValue.length() == 0 )
{
return stringValue;
}

return StringUtils.join( StringUtils.splitByCharacterTypeCamelCase( stringValue ), '_' )
.replace( '-', '_' ).toUpperCase();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.dhis2.fhir.adapter.fhir.repository.impl.dstu3;

/*
* Copyright (c) 2004-2018, University of Oslo
* Copyright (c) 2004-2019, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -31,6 +31,7 @@
import ca.uhn.fhir.context.FhirContext;
import org.dhis2.fhir.adapter.fhir.metadata.model.FhirServerResource;
import org.dhis2.fhir.adapter.fhir.metadata.model.SubscriptionType;
import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirServerResourceRepository;
import org.dhis2.fhir.adapter.fhir.repository.impl.AbstractFhirResourceRepositoryImpl;
import org.dhis2.fhir.adapter.fhir.server.StoredFhirResourceService;
import org.hl7.fhir.dstu3.model.Bundle;
Expand All @@ -53,9 +54,9 @@
@Component
public class Dstu3FhirResourceRepositoryImpl extends AbstractFhirResourceRepositoryImpl
{
public Dstu3FhirResourceRepositoryImpl( @Nonnull StoredFhirResourceService storedItemService, @Nonnull ObjectProvider<List<FhirContext>> fhirContexts )
public Dstu3FhirResourceRepositoryImpl( @Nonnull StoredFhirResourceService storedItemService, @Nonnull FhirServerResourceRepository fhirServerResourceRepository, @Nonnull ObjectProvider<List<FhirContext>> fhirContexts )
{
super( storedItemService, fhirContexts );
super( storedItemService, fhirServerResourceRepository, fhirContexts );
}

@Nonnull
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.dhis2.fhir.adapter.fhir.metadata.model;

/*
* Copyright (c) 2004-2018, University of Oslo
* Copyright (c) 2004-2019, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -88,6 +88,12 @@ public static FhirResourceType getByResource( @Nullable IBaseResource resource )
return frt;
}

@Nullable
public static FhirResourceType getByResourceTypeName( @Nullable String resourceTypeName )
{
return resourcesBySimpleClassName.get( resourceTypeName );
}

private final String resourceTypeName;

private final int order;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.dhis2.fhir.adapter.fhir.metadata.model;

/*
* Copyright (c) 2004-2018, University of Oslo
* Copyright (c) 2004-2019, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -105,6 +105,8 @@ public class FhirServer extends VersionedBaseMetadata implements DataGroup, Seri
@Min( 0 )
private int toleranceMillis;

private boolean remoteSyncEnabled;

@NotNull
@Valid
private SubscriptionDhisEndpoint dhisEndpoint;
Expand Down Expand Up @@ -220,6 +222,18 @@ public void setToleranceMillis( int toleranceMillis )
this.toleranceMillis = toleranceMillis;
}

@Basic
@Column( name = "remote_sync_enabled", nullable = false, columnDefinition = "BOOLEAN DEFAULT FALSE NOT NULL" )
public boolean isRemoteSyncEnabled()
{
return remoteSyncEnabled;
}

public void setRemoteSyncEnabled( boolean remoteSyncEnabled )
{
this.remoteSyncEnabled = remoteSyncEnabled;
}

@Basic
@Column( name = "fhir_version", nullable = false )
@Enumerated( EnumType.STRING )
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.dhis2.fhir.adapter.fhir.metadata.model;

/*
* Copyright (c) 2004-2018, University of Oslo
* Copyright (c) 2004-2019, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -89,6 +89,10 @@ public class FhirServerResource extends VersionedBaseMetadata implements DataGro

private String fhirSubscriptionId;

private ExecutableScript impTransformScript;

private boolean preferred;

@Basic
@Column( name = "fhir_resource_type", nullable = false, length = 30 )
@Enumerated( EnumType.STRING )
Expand Down Expand Up @@ -188,6 +192,30 @@ public void setFhirSubscriptionId( String fhirSubscriptionId )
this.fhirSubscriptionId = fhirSubscriptionId;
}

@ManyToOne
@JoinColumn( name = "imp_transform_script_id" )
public ExecutableScript getImpTransformScript()
{
return impTransformScript;
}

public void setImpTransformScript( ExecutableScript impTransformScript )
{
this.impTransformScript = impTransformScript;
}

@Basic
@Column( name = "preferred", nullable = false, columnDefinition = "BOOLEAN DEFAULT FALSE NOT NULL" )
public boolean isPreferred()
{
return preferred;
}

public void setPreferred( boolean preferred )
{
this.preferred = preferred;
}

@JsonIgnore
@Transient
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.dhis2.fhir.adapter.fhir.metadata.repository;

/*
* Copyright (c) 2004-2018, University of Oslo
* Copyright (c) 2004-2019, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -59,11 +59,17 @@
public interface FhirServerResourceRepository extends JpaRepository<FhirServerResource, UUID>, QuerydslPredicateExecutor<FhirServerResource>, CustomFhirServerResourceRepository
{
@RestResource( exported = false )
@Query( "SELECT r FROM #{#entityName} r JOIN FETCH r.fhirServer s WHERE s=:subscription AND r.fhirResourceType=:fhirResourceType ORDER BY r.id" )
@Query( "SELECT r FROM #{#entityName} r JOIN FETCH r.fhirServer s WHERE s=:fhirServer AND r.fhirResourceType=:fhirResourceType ORDER BY r.id" )
@Nonnull
@Cacheable( key = "{#root.methodName, #a0.id, #a1}" )
@Cacheable( key = "{#root.methodName, #a0.id, #a1}" )
Optional<FhirServerResource> findFirstCached(
@Param( "subscription" ) @Nonnull FhirServer fhirServer, @Param( "fhirResourceType" ) @Nonnull FhirResourceType fhirResourceType );
@Param( "fhirServer" ) @Nonnull FhirServer fhirServer, @Param( "fhirResourceType" ) @Nonnull FhirResourceType fhirResourceType );

@RestResource( exported = false )
@Query( "SELECT r FROM #{#entityName} r JOIN FETCH r.fhirServer s WHERE s=:fhirServerId AND r.fhirResourceType=:fhirResourceType ORDER BY r.preferred DESC, r.id" )
@Nonnull
@Cacheable( key = "{#root.methodName, #a0, #a1}" )
Optional<FhirServerResource> findFirstCached( @Param( "fhirServerId" ) @Nonnull UUID fhirServerId, @Param( "fhirResourceType" ) @Nonnull FhirResourceType fhirResourceType );

@Override
@Nonnull
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.dhis2.fhir.adapter.fhir.metadata.repository;

/*
* Copyright (c) 2004-2018, University of Oslo
* Copyright (c) 2004-2019, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand All @@ -28,6 +28,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import org.dhis2.fhir.adapter.fhir.metadata.model.FhirResourceType;
import org.dhis2.fhir.adapter.fhir.metadata.model.FhirServer;
import org.dhis2.fhir.adapter.fhir.metadata.model.FhirServerSystem;
import org.springframework.cache.annotation.CacheConfig;
Expand All @@ -45,6 +46,7 @@
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

/**
Expand All @@ -59,9 +61,15 @@ public interface FhirServerSystemRepository extends JpaRepository<FhirServerSyst
{
@RestResource( exported = false )
@Nonnull
@Query( "SELECT rss FROM #{#entityName} rss WHERE rss.fhirServer=:subscription" )
@Query( "SELECT rss FROM #{#entityName} rss WHERE rss.fhirServer=:fhirServer" )
@Cacheable( key = "{#root.methodName, #a0.id}" )
Collection<FhirServerSystem> findByFhirServer( @Param( "subscription" ) @Nonnull FhirServer subscription );
Collection<FhirServerSystem> findByFhirServer( @Param( "fhirServer" ) @Nonnull FhirServer fhirServer );

@RestResource( exported = false )
@Nonnull
@Query( "SELECT rss FROM #{#entityName} rss WHERE rss.fhirServer=:fhirServer AND rss.fhirResourceType=:fhirResourceType" )
@Cacheable( key = "{#root.methodName, #a0.id, #a1}" )
Optional<FhirServerSystem> findOneByFhirServerResourceType( @Param( "fhirServer" ) @Nonnull FhirServer fhirServer, @Param( "fhirResourceType" ) @Nonnull FhirResourceType fhirResourceType );

@Override
@Nonnull
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.dhis2.fhir.adapter.fhir.metadata.repository.validator;

/*
* Copyright (c) 2004-2018, University of Oslo
* Copyright (c) 2004-2019, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -29,12 +29,18 @@
*/

import org.apache.commons.lang3.StringUtils;
import org.dhis2.fhir.adapter.fhir.metadata.model.DataType;
import org.dhis2.fhir.adapter.fhir.metadata.model.ExecutableScript;
import org.dhis2.fhir.adapter.fhir.metadata.model.FhirResourceType;
import org.dhis2.fhir.adapter.fhir.metadata.model.FhirServerResource;
import org.dhis2.fhir.adapter.fhir.metadata.model.ScriptType;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import reactor.util.annotation.NonNull;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/**
* Spring Data REST validator for {@link FhirServerResource}.
Expand Down Expand Up @@ -63,10 +69,38 @@ public void validate( Object target, @Nonnull Errors errors )
{
errors.rejectValue( "fhirResourceType", "FhirServerResource.fhirResourceType.null", "FHIR resource type is mandatory." );
}
else
{
checkValidTransformInScript( errors, "impTransformScript", fhirServerResource.getFhirResourceType(), fhirServerResource.getImpTransformScript() );
}
if ( StringUtils.length( fhirServerResource.getFhirCriteriaParameters() ) > FhirServerResource.MAX_CRITERIA_PARAMETERS_LENGTH )
{
errors.rejectValue( "fhirCriteriaParameters", "FhirServerResource.fhirCriteriaParameters.length", new Object[]{ FhirServerResource.MAX_CRITERIA_PARAMETERS_LENGTH },
"FHIR criteria parameters must not be longer than {0} characters." );
}
}

protected static void checkValidTransformInScript( @NonNull Errors errors, @Nonnull String field, @Nonnull FhirResourceType fhirResourceType, @Nullable ExecutableScript executableScript )
{
if ( executableScript == null )
{
return;
}
if ( executableScript.getScript().getScriptType() != ScriptType.TRANSFORM_TO_DHIS )
{
errors.rejectValue( field, "FhirServerResource." + field + ".scriptType", "Assigned script type for incoming transformation must be TRANSFORM_TO_DHIS." );
}
if ( executableScript.getScript().getReturnType() != DataType.BOOLEAN )
{
errors.rejectValue( field, "FhirServerResource." + field + ".returnType", "Assigned return type for incoming transformation script must be BOOLEAN." );
}
if ( (executableScript.getScript().getInputType() != null) && (executableScript.getScript().getInputType().getFhirResourceType() != fhirResourceType) )
{
errors.rejectValue( field, "FhirServerResource." + field + ".inputType", new Object[]{ fhirResourceType }, "Assigned input type for incoming transformation script must be the same as for the resource {0}." );
}
if ( (executableScript.getScript().getOutputType() != null) && (executableScript.getScript().getOutputType().getFhirResourceType() != fhirResourceType) )
{
errors.rejectValue( field, "FhirServerResource." + field + ".inputType", new Object[]{ fhirResourceType }, "Assigned input type for outgoing transformation script must be the same as for the resource {0}." );
}
}
}
Loading

0 comments on commit b8ed06e

Please sign in to comment.