Skip to content

Commit 2640325

Browse files
committed
HAPI upgrade to 8.4.0 (fhir/bpe server, API v2), needed code changes
Fixed inconsistent StructureDefinition snapshot handling. Internal resource created and updated events now always include snapshots. HTTP responses include snapshots if the StructureDefinition resource in the POST or PUT request included a snapshot. New integration test to verify behavior.
1 parent 4b1efc0 commit 2640325

File tree

18 files changed

+6845
-157
lines changed

18 files changed

+6845
-157
lines changed

dsf-bpe/dsf-bpe-process-api-v2-impl/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@
162162
<artifactItem>
163163
<groupId>org.xerial</groupId>
164164
<artifactId>sqlite-jdbc</artifactId>
165-
<version>3.45.1.0</version>
165+
<version>3.49.1.0</version>
166166
</artifactItem>
167167
<artifactItem>
168168
<groupId>ca.uhn.hapi.fhir</groupId>

dsf-bpe/dsf-bpe-server/src/main/resources/bpe/api/v2/allowed-bpe-classes.list

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ com.fasterxml.jackson.core
33
com.fasterxml.jackson.databind
44
com.fasterxml.jackson.datatype
55
com.google.common
6+
com.ctc.wstx.stax.WstxInputFactory
67
dev.dsf.bpe.api
78
jakarta.annotation.Nonnull
89
jakarta.annotation.Nullable

dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/CreateCommand.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import dev.dsf.fhir.dao.jdbc.LargeObjectManager;
3131
import dev.dsf.fhir.event.EventGenerator;
3232
import dev.dsf.fhir.event.EventHandler;
33+
import dev.dsf.fhir.event.ResourceCreatedEvent;
3334
import dev.dsf.fhir.help.ExceptionHandler;
3435
import dev.dsf.fhir.help.ParameterConverter;
3536
import dev.dsf.fhir.help.ResponseGenerator;
@@ -247,12 +248,13 @@ public Optional<BundleEntryComponent> postExecute(Connection connection, EventHa
247248
if (responseResult == null)
248249
{
249250
// retrieving the latest resource from db to include updated references
250-
Resource createdResourceWithResolvedReferences = latestOrErrorIfDeletedOrNotFound(connection,
251-
createdResource);
251+
R createdResourceWithResolvedReferences = latestOrErrorIfDeletedOrNotFound(connection, createdResource);
252+
253+
referenceCleaner.cleanLiteralReferences(createdResourceWithResolvedReferences);
254+
252255
try
253256
{
254-
referenceCleaner.cleanLiteralReferences(createdResourceWithResolvedReferences);
255-
eventHandler.handleEvent(eventGenerator.newResourceCreatedEvent(createdResourceWithResolvedReferences));
257+
eventHandler.handleEvent(createEvent(createdResourceWithResolvedReferences));
256258
}
257259
catch (Exception e)
258260
{
@@ -261,6 +263,8 @@ public Optional<BundleEntryComponent> postExecute(Connection connection, EventHa
261263
e.getMessage());
262264
}
263265

266+
modifyResponseResource(createdResourceWithResolvedReferences);
267+
264268
IdType location = createdResourceWithResolvedReferences.getIdElement().withServerBase(serverBase,
265269
createdResourceWithResolvedReferences.getResourceType().name());
266270

@@ -304,6 +308,15 @@ else if (PreferReturnType.OPERATION_OUTCOME.equals(returnType))
304308
}
305309
}
306310

311+
protected ResourceCreatedEvent createEvent(R eventResource)
312+
{
313+
return eventGenerator.newResourceCreatedEvent(eventResource);
314+
}
315+
316+
protected void modifyResponseResource(R responseResource)
317+
{
318+
}
319+
307320
private R latestOrErrorIfDeletedOrNotFound(Connection connection, Resource resource)
308321
{
309322
try

dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/CreateStructureDefinitionCommand.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import dev.dsf.fhir.dao.StructureDefinitionDao;
1818
import dev.dsf.fhir.dao.jdbc.LargeObjectManager;
1919
import dev.dsf.fhir.event.EventGenerator;
20+
import dev.dsf.fhir.event.ResourceCreatedEvent;
2021
import dev.dsf.fhir.help.ExceptionHandler;
2122
import dev.dsf.fhir.help.ParameterConverter;
2223
import dev.dsf.fhir.help.ResponseGenerator;
@@ -35,6 +36,7 @@ public class CreateStructureDefinitionCommand extends CreateCommand<StructureDef
3536

3637
private final StructureDefinitionDao snapshotDao;
3738

39+
private boolean requestResourceHasSnapshot;
3840
private StructureDefinition resourceWithSnapshot;
3941

4042
public CreateStructureDefinitionCommand(int index, Identity identity, PreferReturnType returnType, Bundle bundle,
@@ -55,6 +57,7 @@ public CreateStructureDefinitionCommand(int index, Identity identity, PreferRetu
5557
public void preExecute(Map<String, IdType> idTranslationTable, Connection connection,
5658
ValidationHelper validationHelper, SnapshotGenerator snapshotGenerator)
5759
{
60+
requestResourceHasSnapshot = resource.hasSnapshot();
5861
resourceWithSnapshot = resource.hasSnapshot() ? resource.copy()
5962
: generateSnapshot(snapshotGenerator, resource.copy());
6063
resource.setSnapshot(null);
@@ -101,4 +104,23 @@ protected StructureDefinition createWithTransactionAndId(LargeObjectManager larg
101104

102105
return created;
103106
}
107+
108+
@Override
109+
protected ResourceCreatedEvent createEvent(StructureDefinition eventResource)
110+
{
111+
if (resourceWithSnapshot != null)
112+
{
113+
resourceWithSnapshot.setIdElement(eventResource.getIdElement().copy());
114+
return super.createEvent(resourceWithSnapshot);
115+
}
116+
else
117+
return super.createEvent(eventResource);
118+
}
119+
120+
@Override
121+
protected void modifyResponseResource(StructureDefinition responseResource)
122+
{
123+
if (requestResourceHasSnapshot)
124+
responseResource.setSnapshot(resourceWithSnapshot.getSnapshot());
125+
}
104126
}

dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/UpdateCommand.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import dev.dsf.fhir.dao.jdbc.LargeObjectManager;
3333
import dev.dsf.fhir.event.EventGenerator;
3434
import dev.dsf.fhir.event.EventHandler;
35+
import dev.dsf.fhir.event.ResourceUpdatedEvent;
3536
import dev.dsf.fhir.help.ExceptionHandler;
3637
import dev.dsf.fhir.help.ParameterConverter;
3738
import dev.dsf.fhir.help.ResponseGenerator;
@@ -414,18 +415,22 @@ private UUID getUuid(Map<String, IdType> idTranslationTable)
414415
public Optional<BundleEntryComponent> postExecute(Connection connection, EventHandler eventHandler)
415416
{
416417
// retrieving the latest resource from db to include updated references
417-
Resource updatedResourceWithResolvedReferences = latestOrErrorIfDeletedOrNotFound(connection, updatedResource);
418+
R updatedResourceWithResolvedReferences = latestOrErrorIfDeletedOrNotFound(connection, updatedResource);
419+
420+
referenceCleaner.cleanLiteralReferences(updatedResourceWithResolvedReferences);
421+
418422
try
419423
{
420-
referenceCleaner.cleanLiteralReferences(updatedResourceWithResolvedReferences);
421-
eventHandler.handleEvent(eventGenerator.newResourceUpdatedEvent(updatedResourceWithResolvedReferences));
424+
eventHandler.handleEvent(createEvent(updatedResourceWithResolvedReferences));
422425
}
423426
catch (Exception e)
424427
{
425428
logger.debug("Error while handling resource updated event", e);
426429
logger.warn("Error while handling resource updated event: {} - {}", e.getClass().getName(), e.getMessage());
427430
}
428431

432+
modifyResponseResource(updatedResourceWithResolvedReferences);
433+
429434
IdType location = updatedResourceWithResolvedReferences.getIdElement().withServerBase(serverBase,
430435
updatedResourceWithResolvedReferences.getResourceType().name());
431436

@@ -452,6 +457,15 @@ else if (PreferReturnType.OPERATION_OUTCOME.equals(returnType))
452457
return Optional.of(resultEntry);
453458
}
454459

460+
protected ResourceUpdatedEvent createEvent(Resource eventResource)
461+
{
462+
return eventGenerator.newResourceUpdatedEvent(eventResource);
463+
}
464+
465+
protected void modifyResponseResource(R responseResource)
466+
{
467+
}
468+
455469
private R latestOrErrorIfDeletedOrNotFound(Connection connection, Resource resource)
456470
{
457471
try

dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/UpdateStructureDefinitionCommand.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.hl7.fhir.r4.model.Bundle;
99
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
1010
import org.hl7.fhir.r4.model.IdType;
11+
import org.hl7.fhir.r4.model.Resource;
1112
import org.hl7.fhir.r4.model.StructureDefinition;
1213
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
1314
import org.slf4j.Logger;
@@ -19,6 +20,7 @@
1920
import dev.dsf.fhir.dao.exception.ResourceVersionNoMatchException;
2021
import dev.dsf.fhir.dao.jdbc.LargeObjectManager;
2122
import dev.dsf.fhir.event.EventGenerator;
23+
import dev.dsf.fhir.event.ResourceUpdatedEvent;
2224
import dev.dsf.fhir.help.ExceptionHandler;
2325
import dev.dsf.fhir.help.ParameterConverter;
2426
import dev.dsf.fhir.help.ResponseGenerator;
@@ -38,6 +40,7 @@ public class UpdateStructureDefinitionCommand extends UpdateCommand<StructureDef
3840

3941
private final StructureDefinitionDao snapshotDao;
4042

43+
private boolean requestResourceHasSnapshot;
4144
private StructureDefinition resourceWithSnapshot;
4245

4346
public UpdateStructureDefinitionCommand(int index, Identity identity, PreferReturnType returnType, Bundle bundle,
@@ -58,6 +61,7 @@ public UpdateStructureDefinitionCommand(int index, Identity identity, PreferRetu
5861
public void preExecute(Map<String, IdType> idTranslationTable, Connection connection,
5962
ValidationHelper validationHelper, SnapshotGenerator snapshotGenerator)
6063
{
64+
requestResourceHasSnapshot = resource.hasSnapshot();
6165
resourceWithSnapshot = resource.hasSnapshot() ? resource.copy()
6266
: generateSnapshot(snapshotGenerator, resource.copy());
6367
resource.setSnapshot(null);
@@ -135,4 +139,23 @@ protected StructureDefinition updateWithTransaction(LargeObjectManager largeObje
135139

136140
return updated;
137141
}
142+
143+
@Override
144+
protected ResourceUpdatedEvent createEvent(Resource eventResource)
145+
{
146+
if (resourceWithSnapshot != null)
147+
{
148+
resourceWithSnapshot.setIdElement(eventResource.getIdElement().copy());
149+
return super.createEvent(resourceWithSnapshot);
150+
}
151+
else
152+
return super.createEvent(eventResource);
153+
}
154+
155+
@Override
156+
protected void modifyResponseResource(StructureDefinition responseResource)
157+
{
158+
if (requestResourceHasSnapshot)
159+
responseResource.setSnapshot(resourceWithSnapshot.getSnapshot());
160+
}
138161
}

dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/jdbc/ReadByUrlDaoJdbc.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ Optional<R> readByUrlAndVersionWithTransaction(Connection connection, String url
105105
if (url == null || url.isBlank())
106106
return Optional.empty();
107107

108-
String versionSql = version != null && !version.isBlank() ? "AND " + resourceColumn + "->>'version' = ? " : "";
108+
String versionSql = version != null && !version.isBlank() ? " AND " + resourceColumn + "->>'version' = ?" : "";
109109
String sql = "SELECT " + resourceColumn + " FROM current_" + resourceTable + " WHERE " + resourceColumn
110-
+ "->>'url' = ? " + versionSql;
110+
+ "->>'url' = ?" + versionSql;
111111

112112
try (PreparedStatement statement = connection.prepareStatement(sql))
113113
{

dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/ValidationConfig.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import dev.dsf.fhir.service.ValidationSupportWithCacheAndEventHandler;
1818
import dev.dsf.fhir.service.ValidationSupportWithFetchFromDb;
1919
import dev.dsf.fhir.service.ValidationSupportWithFetchFromDbWithTransaction;
20-
import dev.dsf.fhir.validation.ResourceInResourceValidator;
2120
import dev.dsf.fhir.validation.ResourceValidator;
2221
import dev.dsf.fhir.validation.ResourceValidatorImpl;
2322
import dev.dsf.fhir.validation.SimpleValidationSupportChain;
@@ -61,8 +60,7 @@ private SimpleValidationSupportChain validationSupportChain(IValidationSupport d
6160
@Bean
6261
public ResourceValidator resourceValidator()
6362
{
64-
return new ResourceInResourceValidator(fhirConfig.fhirContext(),
65-
new ResourceValidatorImpl(fhirConfig.fhirContext(), validationSupport()));
63+
return new ResourceValidatorImpl(fhirConfig.fhirContext(), validationSupport());
6664
}
6765

6866
@Bean

dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/webservice/impl/AbstractResourceServiceImpl.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
import dev.dsf.fhir.dao.jdbc.LargeObjectManager;
4343
import dev.dsf.fhir.event.EventGenerator;
4444
import dev.dsf.fhir.event.EventHandler;
45+
import dev.dsf.fhir.event.ResourceCreatedEvent;
46+
import dev.dsf.fhir.event.ResourceUpdatedEvent;
4547
import dev.dsf.fhir.help.ExceptionHandler;
4648
import dev.dsf.fhir.help.ParameterConverter;
4749
import dev.dsf.fhir.help.ResponseGenerator;
@@ -194,8 +196,6 @@ public Response create(R resource, UriInfo uri, HttpHeaders headers)
194196

195197
referenceCleaner.cleanLiteralReferences(createdResource);
196198

197-
eventHandler.handleEvent(eventGenerator.newResourceCreatedEvent(createdResource));
198-
199199
if (afterCreate != null)
200200
afterCreate.accept(createdResource);
201201

@@ -309,8 +309,7 @@ private Optional<OperationOutcome> checkReference(Resource resource, Connection
309309

310310
private void checkAlreadyExists(HttpHeaders headers) throws WebApplicationException
311311
{
312-
Optional<String> ifNoneExistHeader = getHeaderString(headers, Constants.HEADER_IF_NONE_EXIST,
313-
Constants.HEADER_IF_NONE_EXIST_LC);
312+
Optional<String> ifNoneExistHeader = getHeaderString(headers, Constants.HEADER_IF_NONE_EXIST);
314313

315314
if (ifNoneExistHeader.isEmpty())
316315
return; // header not found, nothing to check against
@@ -377,7 +376,10 @@ protected final Optional<String> getHeaderString(HttpHeaders headers, String...
377376

378377
/**
379378
* Override to modify the given resource before db insert, throw {@link WebApplicationException} to interrupt the
380-
* normal flow
379+
* normal flow.
380+
* <p>
381+
* Default implementation calls the {@link #eventHandler} with a {@link ResourceCreatedEvent} for the created
382+
* resource.
381383
*
382384
* @param resource
383385
* not <code>null</code>
@@ -389,7 +391,7 @@ protected final Optional<String> getHeaderString(HttpHeaders headers, String...
389391
*/
390392
protected Consumer<R> preCreate(R resource) throws WebApplicationException
391393
{
392-
return null;
394+
return createdResource -> eventHandler.handleEvent(eventGenerator.newResourceCreatedEvent(createdResource));
393395
}
394396

395397
@Override
@@ -605,8 +607,6 @@ public Response update(String id, R resource, UriInfo uri, HttpHeaders headers)
605607

606608
referenceCleaner.cleanLiteralReferences(updatedResource);
607609

608-
eventHandler.handleEvent(eventGenerator.newResourceUpdatedEvent(updatedResource));
609-
610610
if (afterUpdate != null)
611611
afterUpdate.accept(updatedResource);
612612

@@ -620,7 +620,10 @@ public Response update(String id, R resource, UriInfo uri, HttpHeaders headers)
620620

621621
/**
622622
* Override to modify the given resource before db update, throw {@link WebApplicationException} to interrupt the
623-
* normal flow. Path id vs. resource.id.idPart is checked before this method is called
623+
* normal flow. Path id vs. resource.id.idPart is checked before this method is called.
624+
* <p>
625+
* Default implementation calls the {@link #eventHandler} with a {@link ResourceUpdatedEvent} for the updated
626+
* resource.
624627
*
625628
* @param resource
626629
* not <code>null</code>
@@ -632,7 +635,7 @@ public Response update(String id, R resource, UriInfo uri, HttpHeaders headers)
632635
*/
633636
protected Consumer<R> preUpdate(R resource)
634637
{
635-
return null;
638+
return updatedResource -> eventHandler.handleEvent(eventGenerator.newResourceUpdatedEvent(updatedResource));
636639
}
637640

638641
@Override

0 commit comments

Comments
 (0)