Skip to content

Commit

Permalink
Fixes issue with generated FHIR server resource IDs.
Browse files Browse the repository at this point in the history
  • Loading branch information
volsch committed Aug 4, 2019
1 parent 87d3054 commit bf65003
Show file tree
Hide file tree
Showing 6 changed files with 273 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,15 @@ public enum DhisResourceType
*/
ORGANIZATION_UNIT( "organisationUnits", "ou", "OrganizationUnitRule" ),

/**
* The program metadata.
*/
PROGRAM_METADATA( "programs", "pm", "ProgramMetadataRule" ),

/**
* The program stage metadata.
*/
PROGRAM_STAGE_METADATA( "programStages", "sm", "ProgramStageMetadataRule" ),

/**
* The program metadata.
*/
PROGRAM_METADATA( "programs", "pm", "ProgramMetadataRule" ),

/**
* Resource is a tracked entity type.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,22 +58,22 @@
*/
public enum FhirResourceType
{
CONDITION( FhirVersion.ALL, "Condition", 19, Collections.emptySet(), Collections.singleton( "Condition" ) ),
DIAGNOSTIC_REPORT( FhirVersion.ALL, "DiagnosticReport", 30, Collections.emptySet(), Collections.singleton( "DiagnosticReport" ) ),
ENCOUNTER( FhirVersion.ALL, "Encounter", 4, Collections.emptySet(), Collections.singleton( "Encounter" ) ),
IMMUNIZATION( FhirVersion.ALL, "Immunization", 22, Collections.emptySet(), Collections.singleton( "Immunization" ) ),
LOCATION( FhirVersion.ALL, "Location", 2, Collections.emptySet(), Collections.singleton( "Location" ) ),
MEDICATION_REQUEST( FhirVersion.ALL, "MedicationRequest", 21, Collections.emptySet(), Collections.singleton( "MedicationRequest" ) ),
OBSERVATION( FhirVersion.ALL, "Observation", 20, Collections.emptySet(), Collections.singleton( "Observation" ) ),
ORGANIZATION( FhirVersion.ALL, "Organization", 1, Collections.emptySet(), Collections.singleton( "Organization" ) ),
PATIENT( FhirVersion.ALL, "Patient", 10, Collections.emptySet(), Collections.singleton( "Patient" ) ),
RELATED_PERSON( FhirVersion.ALL, "RelatedPerson", 11, Collections.emptySet(), Collections.singleton( "RelatedPerson" ) ),
PRACTITIONER( FhirVersion.ALL, "Practitioner", 9, Collections.emptySet(), Collections.singleton( "Practitioner" ) ),
MEASURE_REPORT( FhirVersion.ALL, "MeasureReport", 30, Collections.singleton( "MeasureReport" ), Collections.singleton( "MeasureReport" ) ),
PLAN_DEFINITION( FhirVersion.R4_ONLY, "PlanDefinition", 30, Collections.emptySet(), Collections.singleton( "PlanDefinition" ) ),
QUESTIONNAIRE( FhirVersion.R4_ONLY, "Questionnaire", 31, Collections.emptySet(), Collections.singleton( "Questionnaire" ) ),
CARE_PLAN( FhirVersion.R4_ONLY, "CarePlan", 35, Collections.emptySet(), Collections.singleton( "CarePlan" ) ),
QUESTIONNAIRE_RESPONSE( FhirVersion.R4_ONLY, "QuestionnaireResponse", 40, Collections.emptySet(), Collections.singleton( "QuestionnaireResponse" ) );
CONDITION( FhirVersion.ALL, "Condition", false, 19, Collections.emptySet(), Collections.singleton( "Condition" ) ),
DIAGNOSTIC_REPORT( FhirVersion.ALL, "DiagnosticReport", false, 30, Collections.emptySet(), Collections.singleton( "DiagnosticReport" ) ),
ENCOUNTER( FhirVersion.ALL, "Encounter", false, 4, Collections.emptySet(), Collections.singleton( "Encounter" ) ),
IMMUNIZATION( FhirVersion.ALL, "Immunization", false, 22, Collections.emptySet(), Collections.singleton( "Immunization" ) ),
LOCATION( FhirVersion.ALL, "Location", false, 2, Collections.emptySet(), Collections.singleton( "Location" ) ),
MEDICATION_REQUEST( FhirVersion.ALL, "MedicationRequest", false, 21, Collections.emptySet(), Collections.singleton( "MedicationRequest" ) ),
OBSERVATION( FhirVersion.ALL, "Observation", false, 20, Collections.emptySet(), Collections.singleton( "Observation" ) ),
ORGANIZATION( FhirVersion.ALL, "Organization", false, 1, Collections.emptySet(), Collections.singleton( "Organization" ) ),
PATIENT( FhirVersion.ALL, "Patient", false, 10, Collections.emptySet(), Collections.singleton( "Patient" ) ),
RELATED_PERSON( FhirVersion.ALL, "RelatedPerson", false, 11, Collections.emptySet(), Collections.singleton( "RelatedPerson" ) ),
PRACTITIONER( FhirVersion.ALL, "Practitioner", false, 9, Collections.emptySet(), Collections.singleton( "Practitioner" ) ),
MEASURE_REPORT( FhirVersion.ALL, "MeasureReport", false, 30, Collections.singleton( "MeasureReport" ), Collections.singleton( "MeasureReport" ) ),
PLAN_DEFINITION( FhirVersion.R4_ONLY, "PlanDefinition", true, 30, Collections.emptySet(), Collections.singleton( "PlanDefinition" ) ),
QUESTIONNAIRE( FhirVersion.R4_ONLY, "Questionnaire", true, 31, Collections.emptySet(), Collections.singleton( "Questionnaire" ) ),
CARE_PLAN( FhirVersion.R4_ONLY, "CarePlan", false, 35, Collections.emptySet(), Collections.singleton( "CarePlan" ) ),
QUESTIONNAIRE_RESPONSE( FhirVersion.R4_ONLY, "QuestionnaireResponse", false, 40, Collections.emptySet(), Collections.singleton( "QuestionnaireResponse" ) );

private static final Map<String, FhirResourceType> resourcesBySimpleClassName = Arrays.stream( values() ).flatMap( v -> v.getSimpleClassNames().stream().map( scn -> new SimpleEntry<>( scn, v ) ) )
.collect( Collectors.toMap( SimpleEntry::getKey, SimpleEntry::getValue ) );
Expand All @@ -85,17 +85,21 @@ public static FhirResourceType getByResource( @Nullable IBaseResource resource )
{
return null;
}

FhirResourceType frt;
Class<?> c = resource.getClass();

do
{
frt = resourcesBySimpleClassName.get( c.getSimpleName() );

if ( frt == null )
{
c = c.getSuperclass();
}
}
while ( (frt == null) && (c != null) && (c != Object.class) );

return frt;
}

Expand All @@ -115,6 +119,8 @@ public static FhirResourceType getByResourceTypeName( @Nullable String resourceT

private final String resourceTypeName;

private final boolean syncDhisId;

private final int order;

private final Set<String> transactionalWith;
Expand All @@ -123,10 +129,11 @@ public static FhirResourceType getByResourceTypeName( @Nullable String resourceT

private volatile Set<FhirResourceType> transactionalWithTypes;

FhirResourceType( Set<FhirVersion> fhirVersions, String resourceTypeName, int order, Collection<String> transactionalWith, Collection<String> simpleClassNames )
FhirResourceType( Set<FhirVersion> fhirVersions, String resourceTypeName, boolean syncDhisId, int order, Collection<String> transactionalWith, Collection<String> simpleClassNames )
{
this.fhirVersions = fhirVersions;
this.resourceTypeName = resourceTypeName;
this.syncDhisId = syncDhisId;
this.order = order;
this.transactionalWith = new HashSet<>( transactionalWith );
this.simpleClassNames = Collections.unmodifiableSet( new HashSet<>( simpleClassNames ) );
Expand All @@ -144,6 +151,11 @@ public String getResourceTypeName()
return resourceTypeName;
}

public boolean isSyncDhisId()
{
return syncDhisId;
}

public int getOrder()
{
return order;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public interface FhirResourceRepository
IBaseResource transform( @Nonnull UUID fhirClientId, @Nonnull FhirVersion fhirVersion, @Nullable IBaseResource resource );

@Nonnull
IBaseResource save( @Nonnull FhirClient fhirClient, @Nonnull IBaseResource resource );
IBaseResource save( @Nonnull FhirClient fhirClient, @Nonnull IBaseResource resource, @Nullable String dhisResourceId );

boolean delete( @Nonnull FhirClient fhirClient, @Nonnull IBaseResource resource );
}
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,8 @@ protected boolean saveInternally( @Nonnull DhisResource resource )
}
else
{
final IBaseResource resultingResource = fhirResourceRepository.save( transformerRequest.getFhirClient(), outcome.getResource() );
final IBaseResource resultingResource = fhirResourceRepository
.save( transformerRequest.getFhirClient(), outcome.getResource(), resource.getId() );
// resource may have been set as attribute in transformer context (e.g. shared encounter)
outcome.getResource().setId( resultingResource.getIdElement() );
fhirDhisAssignmentRepository.saveFhirResourceId( outcome.getRule(), transformerRequest.getFhirClient(),
Expand Down Expand Up @@ -482,6 +483,7 @@ public Optional<IBaseResource> read( @Nonnull FhirClient fhirClient, @Nonnull Fh
if ( dhisResource == null )
{
logger.debug( "DHIS resource could not be found." );

return Optional.empty();
}

Expand All @@ -493,6 +495,7 @@ public Optional<IBaseResource> read( @Nonnull FhirClient fhirClient, @Nonnull Fh
if ( transformerRequest == null )
{
logger.debug( "No matching rule has been found." );

return Optional.empty();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ public boolean delete( @Nonnull FhirClient fhirClient, @Nonnull IBaseResource re
"T(org.dhis2.fhir.adapter.fhir.metadata.model.FhirResourceType).getByResource(#resource).getResourceTypeName(), #resource.getIdElement().getIdPart(), true}" )
@Nonnull
@Override
public IBaseResource save( @Nonnull FhirClient fhirClient, @Nonnull IBaseResource resource )
public IBaseResource save( @Nonnull FhirClient fhirClient, @Nonnull IBaseResource resource, @Nullable String dhisResourceId )
{
if ( !fhirClient.getFhirEndpoint().isUseRemote() )
{
Expand All @@ -287,33 +287,36 @@ public IBaseResource save( @Nonnull FhirClient fhirClient, @Nonnull IBaseResourc
final FhirContext fhirContext = fhirContexts.get( fhirClient.getFhirVersion() );
final IGenericClient client = FhirClientUtils.createClient( fhirContext, fhirClient.getFhirEndpoint() );

final IBaseResource preparedResource = prepareResource( resource, dhisResourceId );
final MethodOutcome methodOutcome;

if ( resource.getIdElement().hasIdPart() )
{
try
{
methodOutcome = client.update().resource( resource ).prefer( PreferReturnEnum.REPRESENTATION ).execute();
methodOutcome = client.update().resource( preparedResource ).prefer( PreferReturnEnum.REPRESENTATION ).execute();
}
catch ( PreconditionFailedException e )
{
throw new OptimisticFhirResourceLockException( "Could not update FHIR resource " +
resource.getIdElement() + " because of an optimistic locking failure.", e );
preparedResource.getIdElement() + " because of an optimistic locking failure.", e );
}
}
else
{
methodOutcome = client.create().resource( resource ).prefer( PreferReturnEnum.REPRESENTATION ).execute();
methodOutcome = client.create().resource( preparedResource ).prefer( PreferReturnEnum.REPRESENTATION ).execute();
}

ProcessedItemInfo processedItemInfo = null;

if ( (methodOutcome.getResource() != null) && (methodOutcome.getResource().getMeta() != null) )
{
// resource itself may contain old version ID (even if it should not)
processedItemInfo = ProcessedFhirItemInfoUtils.create( methodOutcome.getResource(), methodOutcome.getId().getVersionIdPart() );
}
else if ( (methodOutcome.getId() != null) && methodOutcome.getId().hasVersionIdPart() )
{
processedItemInfo = ProcessedFhirItemInfoUtils.create( resource, methodOutcome.getId() );
processedItemInfo = ProcessedFhirItemInfoUtils.create( preparedResource, methodOutcome.getId() );
}

if ( processedItemInfo == null )
Expand All @@ -327,9 +330,11 @@ else if ( (methodOutcome.getId() != null) && methodOutcome.getId().hasVersionIdP
}

final IBaseResource result;

if ( methodOutcome.getResource() == null )
{
result = resource;

if ( methodOutcome.getId() != null )
{
result.setId( methodOutcome.getId() );
Expand All @@ -343,6 +348,24 @@ else if ( (methodOutcome.getId() != null) && methodOutcome.getId().hasVersionIdP
return result;
}

@Nonnull
protected <T extends IBaseResource> T prepareResource( @Nonnull T resource, @Nullable String dhisResourceId )
{
final FhirResourceType fhirResourceType = FhirResourceType.getByResource( resource );

if ( fhirResourceType == null )
{
throw new FhirResourceTransformationException( "Could not determine FHIR resource type for " + resource.getClass().getSimpleName() );
}

if ( fhirResourceType.isSyncDhisId() && dhisResourceId != null && !resource.getIdElement().hasIdPart() )
{
resource.setId( dhisResourceId );
}

return resource;
}

@TransactionalEventListener( phase = TransactionPhase.BEFORE_COMMIT, classes = AutoCreatedFhirClientResourceEvent.class )
public void autoCreatedSubscriptionResource( @Nonnull AutoCreatedFhirClientResourceEvent event )
{
Expand Down
Loading

0 comments on commit bf65003

Please sign in to comment.