Skip to content

Commit

Permalink
Enhanced search filtering of FHIR interfaces.
Browse files Browse the repository at this point in the history
  • Loading branch information
volsch committed Mar 18, 2019
1 parent 66fbea5 commit d072191
Show file tree
Hide file tree
Showing 57 changed files with 1,629 additions and 61 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.dhis2.fhir.adapter.dhis;

/*
* 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.
*/

/**
* Thrown if the find operation caused a conflict or a bad request on the server.
*
* @author volsch
*/
public class DhisFindException extends RuntimeException
{
private static final long serialVersionUID = 565765406720494135L;

public DhisFindException( String message, Throwable cause )
{
super( message, cause );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.dhis2.fhir.adapter.dhis.model;

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

import org.springframework.web.util.UriBuilder;

import javax.annotation.Nonnull;
import java.util.List;

/**
* Applies a filter to a URI builder.
*
* @author volsch
*/
public interface UriFilterApplier
{
@Nonnull
<T extends UriBuilder> T add( @Nonnull T uriBuilder, @Nonnull List<String> variables );
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.dhis2.fhir.adapter.dhis.metadata.model.DhisSyncGroup;
import org.dhis2.fhir.adapter.dhis.model.DhisResourceResult;
import org.dhis2.fhir.adapter.dhis.model.Reference;
import org.dhis2.fhir.adapter.dhis.model.UriFilterApplier;

import javax.annotation.Nonnull;
import java.time.Instant;
Expand All @@ -54,7 +55,7 @@ public interface OrganizationUnitService
Optional<OrganizationUnit> findOneRefreshedByReference( @Nonnull Reference reference );

@Nonnull
DhisResourceResult<OrganizationUnit> find( int from, int max );
DhisResourceResult<OrganizationUnit> find( @Nonnull UriFilterApplier uriFilterApplier, int from, int max );

@Nonnull
Instant poll( @Nonnull DhisSyncGroup group, @Nonnull Instant lastUpdated, int toleranceMillis,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.dhis2.fhir.adapter.data.model.ProcessedItemInfo;
import org.dhis2.fhir.adapter.dhis.DhisFindException;
import org.dhis2.fhir.adapter.dhis.metadata.model.DhisSyncGroup;
import org.dhis2.fhir.adapter.dhis.model.DhisResourceResult;
import org.dhis2.fhir.adapter.dhis.model.Reference;
import org.dhis2.fhir.adapter.dhis.model.UriFilterApplier;
import org.dhis2.fhir.adapter.dhis.orgunit.OrganizationUnit;
import org.dhis2.fhir.adapter.dhis.orgunit.OrganizationUnitService;
import org.dhis2.fhir.adapter.dhis.util.DhisPagingQuery;
Expand All @@ -42,6 +44,7 @@
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpClientErrorException;
Expand All @@ -51,8 +54,10 @@
import javax.annotation.Nonnull;
import java.time.Instant;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
Expand Down Expand Up @@ -130,13 +135,27 @@ public Optional<OrganizationUnit> findOneRefreshedByReference( @Nonnull Referenc
@HystrixCommand
@Nonnull
@Override
public DhisResourceResult<OrganizationUnit> find( int from, int max )
public DhisResourceResult<OrganizationUnit> find( @Nonnull UriFilterApplier uriFilterApplier, int from, int max )
{
final DhisPagingQuery pagingQuery = DhisPagingUtils.createPagingQuery( from, max );
final String uri = UriComponentsBuilder.newInstance().path( "/organisationUnits.json" )
final List<String> variables = new ArrayList<>();
final String uri = uriFilterApplier.add( UriComponentsBuilder.newInstance(), variables ).path( "/organisationUnits.json" )
.queryParam( "paging", "true" ).queryParam( "page", pagingQuery.getPage() ).queryParam( "pageSize", pagingQuery.getPageSize() )
.queryParam( "order", "id" ).queryParam( "fields", FIELDS ).toUriString();
final ResponseEntity<DhisOrganizationUnits> result = restTemplate.getForEntity( uri, DhisOrganizationUnits.class );
.queryParam( "order", "id" ).queryParam( "fields", FIELDS ).build( false ).toString();

final ResponseEntity<DhisOrganizationUnits> result;
try
{
result = restTemplate.getForEntity( uri, DhisOrganizationUnits.class, variables.toArray() );
}
catch ( HttpClientErrorException e )
{
if ( e.getStatusCode() == HttpStatus.BAD_REQUEST || e.getStatusCode() == HttpStatus.CONFLICT )
{
throw new DhisFindException( e.getMessage(), e );
}
throw e;
}
final DhisOrganizationUnits organizationUnits = Objects.requireNonNull( result.getBody() );

return new DhisResourceResult<>( (organizationUnits.getOrganizationUnits().size() > pagingQuery.getResultOffset()) ?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.dhis2.fhir.adapter.data.model.ProcessedItemInfo;
import org.dhis2.fhir.adapter.dhis.metadata.model.DhisSyncGroup;
import org.dhis2.fhir.adapter.dhis.model.DhisResourceResult;
import org.dhis2.fhir.adapter.dhis.model.UriFilterApplier;

import javax.annotation.Nonnull;
import java.time.Instant;
Expand Down Expand Up @@ -62,7 +63,7 @@ List<Event> find( @Nonnull String programId, @Nonnull String programStageId,
Event createOrMinimalUpdate( @Nonnull Event event );

@Nonnull
DhisResourceResult<Event> find( @Nonnull String programId, @Nonnull String programStageId, int from, int max );
DhisResourceResult<Event> find( @Nonnull String programId, @Nonnull String programStageId, @Nonnull UriFilterApplier uriFilterApplier, int from, int max );

@Nonnull
Instant poll( @Nonnull DhisSyncGroup group, @Nonnull Instant lastUpdated, int toleranceMillis,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@
import org.apache.commons.lang3.ObjectUtils;
import org.dhis2.fhir.adapter.data.model.ProcessedItemInfo;
import org.dhis2.fhir.adapter.dhis.DhisConflictException;
import org.dhis2.fhir.adapter.dhis.DhisFindException;
import org.dhis2.fhir.adapter.dhis.DhisImportUnsuccessfulException;
import org.dhis2.fhir.adapter.dhis.metadata.model.DhisSyncGroup;
import org.dhis2.fhir.adapter.dhis.model.DataValue;
import org.dhis2.fhir.adapter.dhis.model.DhisResourceResult;
import org.dhis2.fhir.adapter.dhis.model.ImportSummaryWebMessage;
import org.dhis2.fhir.adapter.dhis.model.Status;
import org.dhis2.fhir.adapter.dhis.model.UriFilterApplier;
import org.dhis2.fhir.adapter.dhis.tracker.program.Event;
import org.dhis2.fhir.adapter.dhis.tracker.program.EventService;
import org.dhis2.fhir.adapter.dhis.util.DhisPagingQuery;
Expand All @@ -57,6 +59,7 @@
import javax.annotation.Nonnull;
import java.time.Instant;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -223,13 +226,27 @@ protected Event update( @Nonnull Event event )

@Nonnull
@Override
public DhisResourceResult<Event> find( @Nonnull String programId, @Nonnull String programStageId, int from, int max )
public DhisResourceResult<Event> find( @Nonnull String programId, @Nonnull String programStageId, @Nonnull UriFilterApplier uriFilterApplier, int from, int max )
{
final DhisPagingQuery pagingQuery = DhisPagingUtils.createPagingQuery( from, max );
final String uri = UriComponentsBuilder.newInstance().path( "/events.json" )
final List<String> variables = new ArrayList<>();
final String uri = uriFilterApplier.add( UriComponentsBuilder.newInstance(), variables ).path( "/events.json" )
.queryParam( "skipPaging", "false" ).queryParam( "page", pagingQuery.getPage() ).queryParam( "pageSize", pagingQuery.getPageSize() )
.queryParam( "program", programId ).queryParam( "programStage", programStageId ).queryParam( "ouMode", "ACCESSIBLE" ).queryParam( "fields", FIELDS ).toUriString();
final ResponseEntity<DhisEvents> result = restTemplate.getForEntity( uri, DhisEvents.class );
.queryParam( "program", programId ).queryParam( "programStage", programStageId ).queryParam( "ouMode", "ACCESSIBLE" ).queryParam( "fields", FIELDS )
.build().toString();
final ResponseEntity<DhisEvents> result;
try
{
result = restTemplate.getForEntity( uri, DhisEvents.class, variables.toArray() );
}
catch ( HttpClientErrorException e )
{
if ( e.getStatusCode() == HttpStatus.BAD_REQUEST || e.getStatusCode() == HttpStatus.CONFLICT )
{
throw new DhisFindException( e.getMessage(), e );
}
throw e;
}
final DhisEvents events = Objects.requireNonNull( result.getBody() );

return new DhisResourceResult<>( (events.getEvents().size() > pagingQuery.getResultOffset()) ?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.dhis2.fhir.adapter.data.model.ProcessedItemInfo;
import org.dhis2.fhir.adapter.dhis.metadata.model.DhisSyncGroup;
import org.dhis2.fhir.adapter.dhis.model.DhisResourceResult;
import org.dhis2.fhir.adapter.dhis.model.UriFilterApplier;

import javax.annotation.Nonnull;
import java.time.Instant;
Expand Down Expand Up @@ -65,7 +66,7 @@ Collection<TrackedEntityInstance> findByAttrValue( @Nonnull String typeId,
TrackedEntityInstance createOrUpdate( @Nonnull TrackedEntityInstance trackedEntityInstance );

@Nonnull
DhisResourceResult<TrackedEntityInstance> find( @Nonnull String trackedEntityTypeId, int from, int max );
DhisResourceResult<TrackedEntityInstance> find( @Nonnull String trackedEntityTypeId, @Nonnull UriFilterApplier uriFilterApplier, int from, int max );

@Nonnull
Instant poll( @Nonnull DhisSyncGroup group, @Nonnull Instant lastUpdated, int toleranceMillis,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;
import org.dhis2.fhir.adapter.data.model.ProcessedItemInfo;
import org.dhis2.fhir.adapter.dhis.DhisConflictException;
import org.dhis2.fhir.adapter.dhis.DhisFindException;
import org.dhis2.fhir.adapter.dhis.DhisImportUnsuccessfulException;
import org.dhis2.fhir.adapter.dhis.DhisResourceException;
import org.dhis2.fhir.adapter.dhis.metadata.model.DhisSyncGroup;
Expand All @@ -40,6 +41,7 @@
import org.dhis2.fhir.adapter.dhis.model.DhisResourceType;
import org.dhis2.fhir.adapter.dhis.model.ImportSummaryWebMessage;
import org.dhis2.fhir.adapter.dhis.model.Status;
import org.dhis2.fhir.adapter.dhis.model.UriFilterApplier;
import org.dhis2.fhir.adapter.dhis.sync.DhisLastUpdated;
import org.dhis2.fhir.adapter.dhis.sync.StoredDhisResourceService;
import org.dhis2.fhir.adapter.dhis.tracker.trackedentity.RequiredValueType;
Expand Down Expand Up @@ -68,8 +70,10 @@
import javax.annotation.Nonnull;
import java.time.Instant;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
Expand Down Expand Up @@ -215,13 +219,26 @@ public TrackedEntityInstance createOrUpdate( @Nonnull TrackedEntityInstance trac

@Nonnull
@Override
public DhisResourceResult<TrackedEntityInstance> find( @Nonnull String trackedEntityTypeId, int from, int max )
public DhisResourceResult<TrackedEntityInstance> find( @Nonnull String trackedEntityTypeId, @Nonnull UriFilterApplier uriFilterApplier, int from, int max )
{
final DhisPagingQuery pagingQuery = DhisPagingUtils.createPagingQuery( from, max );
final String uri = UriComponentsBuilder.newInstance().path( "/trackedEntityInstances.json" )
final List<String> variables = new ArrayList<>();
final String uri = uriFilterApplier.add( UriComponentsBuilder.newInstance(), variables ).path( "/trackedEntityInstances.json" )
.queryParam( "skipPaging", "false" ).queryParam( "page", pagingQuery.getPage() ).queryParam( "pageSize", pagingQuery.getPageSize() )
.queryParam( "trackedEntityType", trackedEntityTypeId ).queryParam( "ouMode", "ACCESSIBLE" ).queryParam( "fields", TEI_FIELDS ).toUriString();
final ResponseEntity<TrackedEntityInstances> result = restTemplate.getForEntity( uri, TrackedEntityInstances.class );
.queryParam( "trackedEntityType", trackedEntityTypeId ).queryParam( "ouMode", "ACCESSIBLE" ).queryParam( "fields", TEI_FIELDS ).build().toString();
final ResponseEntity<TrackedEntityInstances> result;
try
{
result = restTemplate.getForEntity( uri, TrackedEntityInstances.class, variables.toArray() );
}
catch ( HttpClientErrorException e )
{
if ( e.getStatusCode() == HttpStatus.BAD_REQUEST || e.getStatusCode() == HttpStatus.CONFLICT )
{
throw new DhisFindException( e.getMessage(), e );
}
throw e;
}
final TrackedEntityInstances instances = Objects.requireNonNull( result.getBody() );

return new DhisResourceResult<>( (instances.getTrackedEntityInstances().size() > pagingQuery.getResultOffset()) ?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import ca.uhn.fhir.rest.annotation.Count;
import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.annotation.RawParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.TokenOrListParam;
import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirClientResourceRepository;
import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirClientSystemRepository;
import org.dhis2.fhir.adapter.fhir.model.FhirVersion;
Expand All @@ -38,6 +45,9 @@
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;

/**
* DSTU3 resource provider.
Expand All @@ -59,4 +69,12 @@ public FhirVersion getFhirVersion()
{
return FhirVersion.DSTU3;
}

@Search( allowUnknownParams = true )
@Nonnull
public IBundleProvider search( @Nullable @Count Integer count, @Nullable @OptionalParam( name = Condition.SP_CODE ) TokenOrListParam filteredCodes, @Nullable @OptionalParam( name = SP_LAST_UPDATED ) DateRangeParam lastUpdatedDateRange,
@Nullable @RawParam Map<String, List<String>> filter )
{
return super.search( count, filteredCodes, lastUpdatedDateRange, filter );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import ca.uhn.fhir.rest.annotation.Count;
import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.annotation.RawParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.TokenOrListParam;
import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirClientResourceRepository;
import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirClientSystemRepository;
import org.dhis2.fhir.adapter.fhir.model.FhirVersion;
Expand All @@ -38,6 +45,9 @@
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;

/**
* DSTU3 resource provider.
Expand All @@ -59,4 +69,12 @@ public FhirVersion getFhirVersion()
{
return FhirVersion.DSTU3;
}

@Search( allowUnknownParams = true )
@Nonnull
public IBundleProvider search( @Nullable @Count Integer count, @Nullable @OptionalParam( name = DiagnosticReport.SP_CODE ) TokenOrListParam filteredCodes, @Nullable @OptionalParam( name = SP_LAST_UPDATED ) DateRangeParam lastUpdatedDateRange,
@Nullable @RawParam Map<String, List<String>> filter )
{
return super.search( count, filteredCodes, lastUpdatedDateRange, filter );
}
}
Loading

0 comments on commit d072191

Please sign in to comment.