Skip to content

Commit 3f44805

Browse files
committed
Adds support for lazy loaded tracked entity instances.
1 parent b7bf8fc commit 3f44805

File tree

34 files changed

+1562
-363
lines changed

34 files changed

+1562
-363
lines changed

app/src/test/java/org/dhis2/fhir/adapter/fhir/server/AbstractBatchBundleFhirRestAppTest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,10 @@ protected void prepareUpdate() throws Exception
101101
"deleted,trackedEntityInstance,trackedEntityType,orgUnit,coordinates,lastUpdated,attributes%5Battribute,value,lastUpdated,storedBy%5D" ) )
102102
.andExpect( method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) )
103103
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-tei-15-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
104-
105104
userDhis2Server.expect( ExpectedCount.once(), requestTo( matchesPattern( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/enrollments.json?program=EPDyQuoRnXk&programStatus=ACTIVE&trackedEntityInstance=*&ouMode=ACCESSIBLE&fields=:all&" +
106105
"order=lastUpdated:desc&pageSize=1" ) ) )
107106
.andExpect( method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) )
108107
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-bundle-enrollment-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
109-
110108
userDhis2Server.expect( ExpectedCount.between( 1, 2 ), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events.json?program=EPDyQuoRnXk&trackedEntityInstance=JeR2Ul4mZfx&ouMode=ACCESSIBLE&fields=deleted,event,orgUnit,program," +
111109
"enrollment,trackedEntityInstance,programStage,status,eventDate,dueDate,coordinate,lastUpdated,dataValues%5BdataElement,value,providedElsewhere,lastUpdated,storedBy%5D&skipPaging=true" ) )
112110
.andExpect( method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) )

app/src/test/java/org/dhis2/fhir/adapter/fhir/server/dstu3/Dstu3ProgramStageFhirRestAppTest.java

Lines changed: 23 additions & 50 deletions
Large diffs are not rendered by default.

app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4ProgramStageFhirRestAppTest.java

Lines changed: 21 additions & 52 deletions
Large diffs are not rendered by default.

dhis/src/main/java/org/dhis2/fhir/adapter/dhis/local/LocalDhisResourceRepositoryTemplate.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,15 @@ public Optional<T> findOneById( @Nonnull String id, @Nonnull Function<String, T>
124124
return Optional.ofNullable( result );
125125
}
126126

127+
public boolean isLocal( @Nonnull String id )
128+
{
129+
final RequestCacheContext context = requestCacheService.getCurrentRequestCacheContext();
130+
final Optional<LocalDhisResourceRepository<T>> repository = getRepository( context );
131+
132+
return repository.map( r -> r.findOneById( id ).map( DhisResource::isLocal ).orElse( false ) ).orElse( false );
133+
134+
}
135+
127136
@Nonnull
128137
public Collection<T> find( @Nonnull Predicate<T> filter, @Nonnull Supplier<Collection<T>> collectionSupplier, boolean localOnly, @Nonnull String methodName, @Nonnull Object... args )
129138
{
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package org.dhis2.fhir.adapter.dhis.model;
2+
3+
/*
4+
* Copyright (c) 2004-2019, University of Oslo
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
* Redistributions of source code must retain the above copyright notice, this
10+
* list of conditions and the following disclaimer.
11+
*
12+
* Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
* Neither the name of the HISP project nor the names of its contributors may
16+
* be used to endorse or promote products derived from this software without
17+
* specific prior written permission.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23+
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26+
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
31+
import javax.annotation.Nonnull;
32+
import javax.annotation.Nullable;
33+
import java.io.Serializable;
34+
35+
/**
36+
* Contains either the ID of the resource or the resource itself.
37+
*
38+
* @param <T> the concrete type of the DHIS2 resource.
39+
* @author volsch
40+
*/
41+
public class IdentifiedDhisResource<T extends DhisResource> implements Serializable
42+
{
43+
private static final long serialVersionUID = -5373285083896395201L;
44+
45+
private final String id;
46+
47+
private final T resource;
48+
49+
public IdentifiedDhisResource( @Nonnull String id )
50+
{
51+
this.id = id;
52+
this.resource = null;
53+
}
54+
55+
public IdentifiedDhisResource( @Nonnull T resource )
56+
{
57+
this.resource = resource;
58+
this.id = null;
59+
}
60+
61+
@Nullable
62+
public String getId()
63+
{
64+
return id;
65+
}
66+
67+
@Nullable
68+
public T getResource()
69+
{
70+
return resource;
71+
}
72+
73+
public boolean hasResource()
74+
{
75+
return resource != null;
76+
}
77+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package org.dhis2.fhir.adapter.dhis.tracker.trackedentity;
2+
3+
/*
4+
* Copyright (c) 2004-2019, University of Oslo
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
* Redistributions of source code must retain the above copyright notice, this
10+
* list of conditions and the following disclaimer.
11+
*
12+
* Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
* Neither the name of the HISP project nor the names of its contributors may
16+
* be used to endorse or promote products derived from this software without
17+
* specific prior written permission.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23+
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26+
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
31+
import org.dhis2.fhir.adapter.dhis.model.IdentifiedDhisResource;
32+
33+
import javax.annotation.Nonnull;
34+
35+
/**
36+
* Identified tracked entity instance.
37+
*
38+
* @author volsch
39+
*/
40+
public class IdentifiedTrackedEntityInstance extends IdentifiedDhisResource<TrackedEntityInstance>
41+
{
42+
private static final long serialVersionUID = 7975425868929861631L;
43+
44+
public IdentifiedTrackedEntityInstance( @Nonnull String id )
45+
{
46+
super( id );
47+
}
48+
49+
public IdentifiedTrackedEntityInstance( @Nonnull TrackedEntityInstance resource )
50+
{
51+
super( resource );
52+
}
53+
}

dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/TrackedEntityService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ void updateGeneratedValues( @Nonnull TrackedEntityInstance trackedEntityInstance
5757
@Nonnull
5858
Optional<TrackedEntityInstance> findOneById( @Nonnull String id );
5959

60+
boolean isLocal( @Nonnull String id );
61+
6062
@Nonnull
6163
Collection<TrackedEntityInstance> findByAttrValueRefreshed( @Nonnull String typeId,
6264
@Nonnull String attributeId, @Nonnull String value, int maxResult );

dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/impl/TrackedEntityServiceImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,12 @@ public Optional<TrackedEntityInstance> findOneById( @Nonnull String id )
225225
return findOneByIdRefreshed( id );
226226
}
227227

228+
@Override
229+
public boolean isLocal( @Nonnull String id )
230+
{
231+
return resourceRepositoryTemplate.isLocal( id );
232+
}
233+
228234
@HystrixCommand( ignoreExceptions = UnauthorizedException.class )
229235
@Nonnull
230236
@Override

dhis/src/test/java/org/dhis2/fhir/adapter/dhis/local/LocalDhisResourceRepositoryTemplateTest.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,68 @@ public void deleteByIdLocal()
174174
Mockito.verifyZeroInteractions( persistCallback );
175175
}
176176

177+
@Test
178+
public void isLocal()
179+
{
180+
final TrackedEntityInstance tei = new TrackedEntityInstance();
181+
final Object resourceKey = new Object();
182+
183+
tei.setLocal( true );
184+
185+
Mockito.doReturn( requestCacheContext ).when( requestCacheService ).getCurrentRequestCacheContext();
186+
Mockito.doReturn( resourceRepositoryContainer ).when( requestCacheContext ).getAttribute(
187+
Mockito.eq( LocalDhisResourceRepositoryTemplate.CONTAINER_REQUEST_CACHE_ATTRIBUTE_NAME ),
188+
Mockito.eq( LocalDhisResourceRepositoryContainer.class ) );
189+
Mockito.doReturn( resourceKey ).when( requestCacheContext ).getAttribute(
190+
Mockito.eq( LocalDhisResourceRepositoryTemplate.RESOURCE_KEY_REQUEST_CACHE_ATTRIBUTE_NAME ), Mockito.eq( Object.class ) );
191+
Mockito.doReturn( resourceRepository ).when( resourceRepositoryContainer ).getRepository( Mockito.eq( TrackedEntityInstance.class ), Mockito.same( persistCallback ) );
192+
Mockito.doReturn( Optional.of( tei ) ).when( resourceRepository ).findOneById( Mockito.eq( "h1234567890" ) );
193+
194+
Assert.assertTrue( template.isLocal( "h1234567890" ) );
195+
196+
Mockito.verifyZeroInteractions( persistCallback );
197+
}
198+
199+
@Test
200+
public void isLocalIncludedNot()
201+
{
202+
final TrackedEntityInstance tei = new TrackedEntityInstance();
203+
final Object resourceKey = new Object();
204+
205+
Mockito.doReturn( requestCacheContext ).when( requestCacheService ).getCurrentRequestCacheContext();
206+
Mockito.doReturn( resourceRepositoryContainer ).when( requestCacheContext ).getAttribute(
207+
Mockito.eq( LocalDhisResourceRepositoryTemplate.CONTAINER_REQUEST_CACHE_ATTRIBUTE_NAME ),
208+
Mockito.eq( LocalDhisResourceRepositoryContainer.class ) );
209+
Mockito.doReturn( resourceKey ).when( requestCacheContext ).getAttribute(
210+
Mockito.eq( LocalDhisResourceRepositoryTemplate.RESOURCE_KEY_REQUEST_CACHE_ATTRIBUTE_NAME ), Mockito.eq( Object.class ) );
211+
Mockito.doReturn( resourceRepository ).when( resourceRepositoryContainer ).getRepository( Mockito.eq( TrackedEntityInstance.class ), Mockito.same( persistCallback ) );
212+
Mockito.doReturn( Optional.of( tei ) ).when( resourceRepository ).findOneById( Mockito.eq( "h1234567890" ) );
213+
214+
Assert.assertFalse( template.isLocal( "h1234567890" ) );
215+
216+
Mockito.verifyZeroInteractions( persistCallback );
217+
}
218+
219+
@Test
220+
public void isLocalNotIncluded()
221+
{
222+
final TrackedEntityInstance tei = new TrackedEntityInstance();
223+
final Object resourceKey = new Object();
224+
225+
Mockito.doReturn( requestCacheContext ).when( requestCacheService ).getCurrentRequestCacheContext();
226+
Mockito.doReturn( resourceRepositoryContainer ).when( requestCacheContext ).getAttribute(
227+
Mockito.eq( LocalDhisResourceRepositoryTemplate.CONTAINER_REQUEST_CACHE_ATTRIBUTE_NAME ),
228+
Mockito.eq( LocalDhisResourceRepositoryContainer.class ) );
229+
Mockito.doReturn( resourceKey ).when( requestCacheContext ).getAttribute(
230+
Mockito.eq( LocalDhisResourceRepositoryTemplate.RESOURCE_KEY_REQUEST_CACHE_ATTRIBUTE_NAME ), Mockito.eq( Object.class ) );
231+
Mockito.doReturn( resourceRepository ).when( resourceRepositoryContainer ).getRepository( Mockito.eq( TrackedEntityInstance.class ), Mockito.same( persistCallback ) );
232+
Mockito.doReturn( Optional.empty() ).when( resourceRepository ).findOneById( Mockito.eq( "h1234567890" ) );
233+
234+
Assert.assertFalse( template.isLocal( "h1234567890" ) );
235+
236+
Mockito.verifyZeroInteractions( persistCallback );
237+
}
238+
177239
@Test
178240
public void findOneByIdNoLocal()
179241
{

dhis/src/test/java/org/dhis2/fhir/adapter/dhis/tracker/trackedentity/impl/TrackedEntityServiceImplTest.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,45 @@ public void findLocal() throws IOException
154154
mockServer.verify();
155155
}
156156

157+
@Test
158+
public void isLocal() throws IOException
159+
{
160+
mockServer.expect( ExpectedCount.once(), requestTo( "http://localhost:8080/api/trackedEntityInstances.json?strategy=CREATE" ) )
161+
.andExpect( content().contentTypeCompatibleWith( MediaType.APPLICATION_JSON ) )
162+
.andExpect( content().json( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/tracker/program/impl/createTrackedEntityInstance.json", StandardCharsets.UTF_8 ) ) )
163+
.andExpect( method( HttpMethod.POST ) ).andRespond( withSuccess( IOUtils.resourceToByteArray( "/org/dhis2/fhir/adapter/dhis/tracker/program/impl/createTrackedEntityInstance-response.json" ), MediaType.APPLICATION_JSON ) );
164+
165+
final TrackedEntityInstance trackedEntityInstance = new TrackedEntityInstance( trackedEntityType, "Jskdsjeua1s", true );
166+
trackedEntityInstance.setOrgUnitId( "pMEnu7BjqMz" );
167+
168+
try ( final RequestCacheContext cacheContext = requestCacheService.createRequestCacheContext() )
169+
{
170+
cacheContext.setAttribute( LocalDhisResourceRepositoryTemplate.CONTAINER_REQUEST_CACHE_ATTRIBUTE_NAME,
171+
new LocalDhisResourceRepositoryContainerImpl( Collections.singleton( TrackedEntityInstance.class ) ) );
172+
173+
final TrackedEntityInstance createdTrackedEntityInstance = service.createOrUpdate( trackedEntityInstance );
174+
Assert.assertTrue( service.isLocal( "Jskdsjeua1s" ) );
175+
}
176+
}
177+
178+
@Test
179+
public void isLocalNot()
180+
{
181+
try ( final RequestCacheContext cacheContext = requestCacheService.createRequestCacheContext() )
182+
{
183+
Assert.assertFalse( service.isLocal( "Jskdsjeua1s" ) );
184+
}
185+
}
186+
187+
@Test
188+
public void isLocalNoContextNot()
189+
{
190+
try ( final RequestCacheContext cacheContext = requestCacheService.createRequestCacheContext() )
191+
{
192+
Assert.assertFalse( service.isLocal( "Jskdsjeua1s" ) );
193+
}
194+
}
195+
157196
@Test
158197
public void findOneById() throws IOException
159198
{

0 commit comments

Comments
 (0)