FHIR Storage processors perform work using a FHIR Storage module.
smile:persistence/resourceOperationProcessorResource Operations messages posted to the resource-operation-message-in-topic will get processed by the module with id persistence.
<routes xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="kafka:resource-operation-message-in-topic?brokers=localhost:9092"/>
<to uri="smile:persistence/resourceOperationProcessor"/>
</route>
</routes>
This processor accepts a FHIR Transaction or a FHIR Batch Bundle as input and submits it to a FHIR Storage module for processing. FHIR Transactions are commonly used as a mechanism for submitting and loading data into a FHIR repository. They are generally the most efficient way of accomplishing this task, especially at large scale.
smile:persistence/bundleProcessorbundleProcessorResponseBundle - An IBaseBundle containing the transaction/batch response. This bundle contains details about the outcomes of the individual items in the transaction/batch.bundleProcessorProcessingTime - A Long containing the processing time in milliseconds.bundleProcessorStartTime - A java.util.Date containing the timestamp when processing started.failedEntryBundle - An IBaseBundle containing any entries that failed processing (only present when useBatchOnFinalAttempt=true and some entries fail).The following parameters are available to this processor:
retries=2 means that if the initial attempt to process the transaction fails, it will be retried two more times before giving up and throwing an exception. This parameter can be useful when data being submitted is likely to have collisions, meaning concurrent processing is likely to be modifying the same resources. Value should be a positive integer, or 0 (which is the default). When this parameter is used, the following parameters may also be added:
useBatchOnFinalAttempt=true is specified, a submitted FHIR Transaction bundle will be converted into a FHIR Batch bundle prior to the final retry attempt. This can be useful if you are loading transaction bundles containing unrelated resources (i.e. resources which to not have references to each other within the Bundle) and want to ensure that the failure to process one resource does not prevent the loading of another. Value should be true or false (which is the default).Bundles posted to the bundle-in-topic will get processed by the module with id persistence. A log entry will be emitted to the system log after every 100 bundles has been processed.
Authentication parameters for the Kafka consumer (<from...>) are not included here and may be required, but several important parameters are included:
| groupId=my-group-id | The Consumer Group ID must be specified in order to ensure that topic offsets are preserved between restarts of the system. The exact value can be any string, but it must never change or be reused by other applications. |
| maxPollRecords=1 | This setting indicates to Kafka that messages should be consumed one-by-one. This is important because by default Kafka uses large batches and expects that they will be processed very quickly, which is more appropriate for large numbers of very small payloads which require minimal processing each. This is not typically the case in a FHIR server, so a small poll size is chosen. |
|
allowManualCommit=true autoCommitEnable=false |
These are required in order to use the kafkaManualCommit processor at the end of the flow. This processor ensures that the topic offset (the current position within the queue) is not advanced until the message has been successfully processed. |
| autoOffsetReset=earliest | This setting instructs the Kafka consumer to begin at the very beginning of the topic, consuming messages that were produced (added to the topic) before Smile CDR was started. |
This route receives messages from a Kafka topic, where each message on the topic should contain a FHIR Transaction Bundle or a FHIR Batch Bundle. The messages are routed for transaction/batch processing on the FHIR Storage module names persistence.
This route uses a Kafka manual commit only after the message has been processed successfully, and does not have any error handler. This means that any failing messages will be retried indefinitely until processing the message succeeds.
<route>
<from uri="kafka:bundle-in-topic?brokers=localhost:9092&groupId=my-group-id&maxPollRecords=1&allowManualCommit=true&autoCommitEnable=false&autoOffsetReset=earliest"/>
<to uri="smile:persistence/bundleProcessor&logProgressInterval=100"/>
<to uri="smile:clustermgr/kafkaManualCommit" />
</route>
The following example shows a processor which retries twice, and delivers the payload to a failure topic (ie. a Dead Letter Queue) if the final processing attempt fails. Messages on the DLQ topic, named dlq-topic, will contain the failing FHIR transaction.
Note that the Kafka manual commit is only invoked after a successful processed message has completed. This means that if a long series of failing messages is encountered and no messages are successfully processed before the Smile CDR process is terminated, the consumer offset will not be incremented and these failing messages may be processed again by a Smile CDR process which is started later.
<route>
<errorHandler>
<deadLetterChannel deadLetterUri="kafka:dlq-topic?brokers=localhost:9092">
<redeliveryPolicy maximumRedeliveries="3" redeliveryDelay="250"/>
</deadLetterChannel>
</errorHandler>
<from uri="kafka:delivery-topic-with-dlq?brokers=localhost:9092&groupId=my-group-id&maxPollRecords=1&allowManualCommit=true&autoCommitEnable=false&autoOffsetReset=earliest"/>
<to uri="smile:persistence/bundleProcessor?logProgressInterval=5"/>
<to uri="smile:clustermgr/kafkaManualCommit" />
</route>
The following example shows a processor which retries twice, and then attempts the final processing using a FHIR Batch instead of a FHIR Transaction. The batch processing mode is slower than the transaction processing mode, but means that the system will process as many entries as it can. If any entries fail on the final attempt, then a new FHIR Batch Bundle containing the failing entries will be sent to the Kafka dlq-failed-entry-topic topic.
This kind of route can be used in cases where your FHIR transaction bundles contain a large number of unrelated resources, and it is therefore desirable to process as many of them as possible even if one or more of them is unprocessable. This route can result in these transaction bundles being partially processed, with the remaining partial bundle ending up in the Dead Letter Queue.
<route>
<from uri="kafka:guaranteed-delivery-topic?brokers=localhost:9092&groupId=my-group-id&maxPollRecords=1&allowManualCommit=true&autoCommitEnable=false&autoOffsetReset=earliest"/>
<to uri="smile:persistence/bundleProcessor?logProgressInterval=5&retries=3&retryDelayMin=50&retryDelayMax=100&useBatchOnFinalAttempt=true"/>
<choice>
<when>
<variable>failedEntryBundle</variable>
<to uri="kafka:dlq-failed-entry-topic?brokers=localhost:9092" variableSend="failedEntryBundle"/>
</when>
</choice>
<to uri="smile:clustermgr/kafkaManualCommit" />
</route>
smile:persistence/ndjsonToBundleProcessorIBaseBundles. The optional parameter type can be used to specify the kind of bundle to create: transaction (default, if none specified), or batch. This bundle can then be passed to a bundleProcessor processor to persist the bundle to the repository.
Additionally, if the optional parameter ensureHomogeneousResourceTypes is defined and set to true, NDJSON parsing will fail if resources of different types are encountered in the same NDJSON file.Explicitly defining the output bundle as a transaction bundle.
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="my-route">
<from uri="kafka:bundle-in-topic?brokers=localhost:9092"/>
<to uri="smile:persistence/ndjsonToBundleProcessor?type=transaction"/>
<!-- to persist the result of the transformation -->
<to uri="smile:persistence/bundleProcessor"/>
</route>
</routes>
Failing processing if NDJSON source has multiple resource types when only one is expected.
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="my-route">
<from uri="kafka:bundle-in-topic?brokers=localhost:9092"/>
<to uri="smile:persistence/ndjsonToBundleProcessor?ensureHomogeneousResourceTypes=true"/>
<!-- to persist the result of the transformation -->
<to uri="smile:persistence/bundleProcessor"/>
</route>
</routes>
This processor accepts a single FHIR resource as input and performs a create, update, or delete operation directly on the FHIR Storage module. This provides a more efficient way to process individual resources without having to wrap them in a Bundle or ResourceOperationMessage. Note that this route is not designed to handle Bundle resources which have a type of transaction or batch. To ingest such a bundle, see the Bundle Processor.
smile:persistence/singleResourceProcessoroutcome - IBaseOperationOutcome containing the result of the operationresourceId - String containing the unqualified, versionless ID of the processed resource (e.g., Patient/123) (if applicable)The following parameters are available to this processor:
CREATE - Create a new resource. If a user-supplied ID is present in the resource body, it will be ignored.UPDATE - Update an existing resource. If a user-supplied id is missing from the resource body, the operation will fail. The ID must be present.DELETE - Delete an existing resource. If a user-supplied id is missing from the resource body, the operation will fail. The ID must be present.The following example shows a processor that receives a FHIR Patient resource from a kafka topic,and creates it in the FHIR Storage module with ID persistence.
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="create-patient">
<from uri="kafka:resource-in-topic?brokers=localhost:9092&groupId=my-group-id"/>
<to uri="smile:persistence/singleResourceProcessor?method=CREATE"/>
</route>
</routes>
This example shows how to update an existing resource in a specific partition. The route receives the resource from a Kafka topic and updates it in partition 1 of the FHIR Storage module.
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="update-resource">
<from uri="kafka:resource-update-topic?brokers=localhost:9092&groupId=resource-update-group"/>
<to uri="smile:persistence/singleResourceProcessor?method=UPDATE&partitionId=1"/>
</route>
</routes>
The following example shows a route that deletes a FHIR resource based on messages in a kafka topic.
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="delete-resource">
<from uri="kafka:resource-delete-topic?brokers=localhost:9092&groupId=delete-group"/>
<to uri="smile:persistence/singleResourceProcessor?method=DELETE"/>
</route>
</routes>
This processor validates the FHIR resource in the exchange body against the validation configuration (loaded Implementation Guides, profiles, and terminology) of a FHIR Storage module, without making an HTTP $validate round-trip. The resource is validated as-is and is never persisted. This is useful for screening resources flowing through a Camel route before they are stored or forwarded to another system.
smile:persistence/validateBundle is validated as a single unit, producing one OperationOutcome.outcome (configurable, see outcomeVariable) – an IBaseOperationOutcome containing the validation issues.validationPassed (configurable, see validationSuccessVariable) – a Boolean that is true when the resource has no ERROR or FATAL issues.The module id in the URI is required and names the persistence module whose validation configuration (loaded IGs/profiles, terminology) backs the validation.
The following parameters are available to this processor:
OperationOutcome. If the highest severity among the validation issues is at or above this level, the exception is thrown. Accepted values are INFORMATION, WARNING, ERROR (the default), FATAL, or none / never to disable throwing entirely (branch/inspect mode). The default of ERROR means the route fails when the resource has any ERROR or FATAL issue.meta.profile.true, the exchange body is replaced with the OperationOutcome after validation. Value should be true or false (which is the default).OperationOutcome. Defaults to outcome.Boolean. Defaults to validationPassed.This is the default behaviour. Resources that fail validation cause the processor to throw an UnprocessableEntityException, which is handled by an onException block. Valid resources continue to the FHIR Storage module to be persisted.
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="validate-then-store">
<from uri="kafka:resource-in-topic?brokers=localhost:9092&groupId=validate-group"/>
<onException>
<exception>ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException</exception>
<handled><constant>true</constant></handled>
<!-- The OperationOutcome is available on the outcome variable -->
<to uri="kafka:invalid-resource-topic?brokers=localhost:9092"/>
</onException>
<!-- Throws on any ERROR/FATAL issue (failOnSeverity defaults to ERROR) -->
<to uri="smile:persistence/validate"/>
<to uri="smile:persistence/singleResourceProcessor?method=CREATE"/>
</route>
</routes>
Setting failOnSeverity=none disables throwing, so the route can inspect the validationPassed variable and branch with a choice. Both valid and invalid resources are routed explicitly.
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="validate-and-branch">
<from uri="kafka:resource-in-topic?brokers=localhost:9092&groupId=branch-group"/>
<!-- Never throws; always sets validationPassed and outcome -->
<to uri="smile:persistence/validate?failOnSeverity=none"/>
<choice>
<when>
<simple>${variable.validationPassed} == true</simple>
<to uri="smile:persistence/singleResourceProcessor?method=CREATE"/>
</when>
<otherwise>
<to uri="kafka:invalid-resource-topic?brokers=localhost:9092"/>
</otherwise>
</choice>
</route>
</routes>
Setting replaceBody=true replaces the exchange body with the OperationOutcome. This example validates against a specific profile and returns the outcome over an HTTP endpoint.
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="validate-and-return-outcome">
<from uri="netty-http:http://0.0.0.0:8888/validate"/>
<convertBodyTo type="org.hl7.fhir.instance.model.api.IBaseResource"/>
<!-- Validate against an explicit profile and emit the OperationOutcome as the body -->
<to uri="smile:persistence/validate?profile=http://example.org/fhir/StructureDefinition/my-patient&failOnSeverity=none&replaceBody=true"/>
</route>
</routes>
The ValueSet $expand processor executes the FHIR ValueSet $expand operation to expand a ValueSet into a list of codes. This is useful for obtaining the full set of codes contained in a ValueSet for validation, display, or other purposes.
smile:persistence/expandValueSetProcessorThe following FHIR $expand parameters are supported:
Either url or valueSet must be provided.
The following example accepts ValueSet expansion requests via HTTP POST and returns the expanded ValueSet:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="expand-valueset">
<from uri="jetty:http://0.0.0.0:8888/expand-valueset"/>
<to uri="smile:persistence/expandValueSetProcessor"/>
</route>
</routes>
This example demonstrates expanding a ValueSet with a text filter applied. Users can POST a Parameters resource to the HTTP endpoint.
Input (HTTP POST body): A Parameters resource containing the ValueSet URL and filter text:
{
"resourceType": "Parameters",
"parameter": [
{
"name": "url",
"valueUri": "http://hl7.org/fhir/ValueSet/condition-code"
},
{
"name": "filter",
"valueString": "diabetes"
}
]
}
Output (HTTP response body): A ValueSet resource with an expansion containing only codes matching the filter:
{
"resourceType": "ValueSet",
"url": "http://hl7.org/fhir/ValueSet/condition-code",
"expansion": {
"identifier": "urn:uuid:12345678-1234-1234-1234-123456789abc",
"timestamp": "2024-01-15T10:30:00Z",
"contains": [
{
"system": "http://snomed.info/sct",
"code": "73211009",
"display": "Diabetes mellitus"
},
{
"system": "http://snomed.info/sct",
"code": "44054006",
"display": "Type 2 diabetes mellitus"
}
]
}
}
<route id="expand-filtered-valueset">
<from uri="netty-http:http://0.0.0.0:8889/expand-filtered"/>
<convertBodyTo type="java.lang.String"/>
<convertBodyTo type="org.hl7.fhir.instance.model.api.IBaseResource"/>
<to uri="smile:persistence/expandValueSetProcessor"/>
</route>
Users can invoke this route using curl:
curl -X POST http://localhost:8889/expand-filtered \
-H "Content-Type: application/fhir+json" \
-d '{
"resourceType": "Parameters",
"parameter": [
{
"name": "url",
"valueUri": "http://hl7.org/fhir/ValueSet/condition-code"
},
{
"name": "filter",
"valueString": "diabetes"
}
]
}'
The ValueSet $validate-code processor executes the FHIR ValueSet $validate-code operation to validate whether a code is in a given ValueSet.
smile:persistence/valueSetValidateCodeProcessorThe following FHIR $validate-code parameters are supported:
The following Camel exchange headers are supported:
IIdType or a String (e.g., "ValueSet/my-valueset-id"). When set, validation is performed against the specific ValueSet instance (equivalent to POST /ValueSet/[id]/$validate-code) rather than requiring a url parameter. This is useful when you want to validate against a ValueSet by its resource ID rather than its canonical URL.The processor returns a Parameters resource with the following values:
true if the code is valid, false otherwiseThe following example validates codes received from a Kafka topic against a ValueSet:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="validate-valueset-code">
<from uri="kafka:code-validation-topic?brokers=localhost:9092&groupId=validation-group"/>
<!-- Input: Parameters with url, code, and system -->
<to uri="smile:persistence/valueSetValidateCodeProcessor"/>
<!-- Output: Parameters with result (true/false), message, display -->
</route>
</routes>
This example demonstrates validating a code and routing based on whether it's valid:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="validate-and-route">
<from uri="direct:validate-code"/>
<to uri="smile:persistence/valueSetValidateCodeProcessor"/>
<choice>
<when>
<simple>${body.getParameter('result').getValue().getValue()} == 'true'</simple>
<to uri="direct:valid-codes"/>
</when>
<otherwise>
<to uri="direct:invalid-codes"/>
</otherwise>
</choice>
</route>
</routes>
This example demonstrates validating a code against a specific ValueSet instance using its resource ID rather than its canonical URL. The CamelFhirResourceId header specifies the ValueSet to validate against:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="validate-code-by-valueset-id">
<from uri="direct:validate-code-instance"/>
<!-- Set the ValueSet resource ID for instance-level operation -->
<setHeader name="CamelFhirResourceId">
<constant>ValueSet/1114</constant>
</setHeader>
<!-- Input: Parameters with code and system (url not required when using resource ID) -->
<to uri="smile:persistence/valueSetValidateCodeProcessor"/>
<!-- Output: Parameters with result (true/false), message, display -->
</route>
</routes>
The CodeSystem $validate-code processor executes the FHIR CodeSystem $validate-code operation to validate whether a code exists in a given CodeSystem. Unlike the ValueSet version, this validates directly against a CodeSystem without composition rules.
smile:persistence/codeSystemValidateCodeProcessorThe following FHIR $validate-code parameters are supported:
The following Camel exchange headers are supported:
IIdType or a String (e.g., "CodeSystem/my-codesystem-id"). When set, validation is performed against the specific CodeSystem instance (equivalent to POST /CodeSystem/[id]/$validate-code) rather than requiring a url parameter. This is useful when you want to validate against a CodeSystem by its resource ID rather than its canonical URL.The processor returns a Parameters resource with the following values:
true if the code is valid, false otherwiseThe following example validates codes directly against a CodeSystem:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="validate-codesystem-code">
<from uri="direct:validate-codesystem"/>
<!-- Input: Parameters with url and code -->
<to uri="smile:persistence/codeSystemValidateCodeProcessor"/>
<!-- Output: Parameters with result (true/false), message, display -->
</route>
</routes>
This example demonstrates validating a code against a specific CodeSystem instance using its resource ID rather than its canonical URL. The CamelFhirResourceId header specifies the CodeSystem to validate against:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="validate-code-by-codesystem-id">
<from uri="direct:validate-codesystem-instance"/>
<!-- Set the CodeSystem resource ID for instance-level operation -->
<setHeader name="CamelFhirResourceId">
<constant>CodeSystem/123</constant>
</setHeader>
<!-- Input: Parameters with code (url not required when using resource ID) -->
<to uri="smile:persistence/codeSystemValidateCodeProcessor"/>
<!-- Output: Parameters with result (true/false), message, display -->
</route>
</routes>
| Aspect | ValueSet $validate-code | CodeSystem $validate-code |
|---|---|---|
| Validates Against | ValueSet (may include multiple CodeSystems) | Single CodeSystem |
| Composition Rules | Applies ValueSet include/exclude rules | Direct code lookup only |
| Use Case | Validate against clinical value sets | Validate code exists in system |
| Processor URI | valueSetValidateCodeProcessor | codeSystemValidateCodeProcessor |
The CodeSystem $lookup processor executes the FHIR CodeSystem $lookup operation to retrieve details about a specific code in a CodeSystem. This can be used to obtain display text, properties, and other information about a code.
smile:persistence/codeSystemLookupProcessorThe following FHIR $lookup parameters are supported:
Either code and system, or coding must be provided.
The processor returns a Parameters resource with the following values:
The following example looks up codes received from a Kafka topic:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="lookup-code">
<from uri="kafka:code-lookup-topic?brokers=localhost:9092&groupId=lookup-group"/>
<!-- Input: Parameters with code and system -->
<to uri="smile:persistence/codeSystemLookupProcessor"/>
<!-- Output: Parameters with name, version, display, property -->
</route>
</routes>
This example accepts lookup requests via HTTP POST. Users can submit a Parameters resource containing the code and system to look up:
Input (HTTP POST body):
{
"resourceType": "Parameters",
"parameter": [
{
"name": "code",
"valueCode": "39156-5"
},
{
"name": "system",
"valueUri": "http://loinc.org"
}
]
}
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="lookup-code-http">
<from uri="netty-http:http://0.0.0.0:8888/lookup-code"/>
<convertBodyTo type="java.lang.String"/>
<convertBodyTo type="org.hl7.fhir.instance.model.api.IBaseResource"/>
<to uri="smile:persistence/codeSystemLookupProcessor"/>
</route>
</routes>
Users can invoke this route using curl:
curl -X POST http://localhost:8888/lookup-code \
-H "Content-Type: application/fhir+json" \
-d '{
"resourceType": "Parameters",
"parameter": [
{
"name": "code",
"valueCode": "39156-5"
},
{
"name": "system",
"valueUri": "http://loinc.org"
}
]
}'
The ConceptMap $translate processor executes the FHIR ConceptMap $translate operation to translate codes between code systems using ConceptMap resources. This is useful for mapping codes from one system to another, such as translating from a local code system to a standard terminology.
smile:persistence/conceptMapTranslateProcessorThe following FHIR $translate parameters are supported:
Either code and system, or coding, or codeableConcept must be provided.
The following Camel exchange headers are supported:
IIdType or a String (e.g., "ConceptMap/123"). When set, translation is performed against the specific ConceptMap instance (equivalent to POST /ConceptMap/[id]/$translate) rather than requiring a url parameter. This is useful when you want to translate using a ConceptMap by its resource ID rather than its canonical URL.The processor returns a Parameters resource with the following values:
true if a translation was found, false otherwiseThe following example translates codes received from a Kafka topic:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="translate-code">
<from uri="kafka:code-translate-topic?brokers=localhost:9092&groupId=translate-group"/>
<!-- Input: Parameters with code, system, and target -->
<to uri="smile:persistence/conceptMapTranslateProcessor"/>
<!-- Output: Parameters with result, message, match -->
</route>
</routes>
This example demonstrates translating a code and routing based on whether a translation was found:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="translate-and-route">
<from uri="direct:translate-code"/>
<to uri="smile:persistence/conceptMapTranslateProcessor"/>
<choice>
<when>
<simple>${body.getParameter('result').getValue().getValue()} == 'true'</simple>
<to uri="direct:translation-found"/>
</when>
<otherwise>
<to uri="direct:no-translation"/>
</otherwise>
</choice>
</route>
</routes>
This example demonstrates translating a code using a specific ConceptMap instance identified by its resource ID rather than its canonical URL. The CamelFhirResourceId header specifies the ConceptMap to use:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="translate-code-by-conceptmap-id">
<from uri="direct:translate-code-instance"/>
<!-- Set the ConceptMap resource ID for instance-level operation -->
<setHeader name="CamelFhirResourceId">
<constant>ConceptMap/123</constant>
</setHeader>
<!-- Input: Parameters with code and system (url not required when using resource ID) -->
<to uri="smile:persistence/conceptMapTranslateProcessor"/>
<!-- Output: Parameters with result, message, match -->
</route>
</routes>
The In-Place Translate processor applies in-place code translation to a FHIR resource flowing through a Camel route. It translates all codings on the resource to a configured target code system using ConceptMap $translate, adding translated codings alongside the originals. The (possibly modified) resource is placed back onto the exchange body.
smile:persistence/inplaceTranslateProcessor?targetSystem=http://loinc.orghttp://loinc.org). Validated at route startup.The following Camel route reads Observations from a Kafka topic, applies in-place LOINC translation, and stores the result:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="inplace-translate-observation">
<from uri="kafka:observations-in?brokers=localhost:9092&groupId=translate-group&maxPollRecords=1&allowManualCommit=true&autoCommitEnable=false"/>
<!-- Translate codings to LOINC in-place -->
<to uri="smile:persistence/inplaceTranslateProcessor?targetSystem=http://loinc.org"/>
<!-- Persist the (possibly translated) resource -->
<to uri="smile:persistence/singleResourceProcessor"/>
<to uri="smile:clustermgr/kafkaManualCommit"/>
</route>
</routes>
For the complete feature description, including the alternative storage interceptor activation method, see In-Place Code Translation.
The Resource $merge processor executes the FHIR Patient $merge operation to merge two patient records. This operation merges source patient data into a target patient, updating all references and marking the source patient as inactive or optionally deleting the source patient.
smile:persistence/patientMergeProcessorThe following FHIR $merge parameters are supported:
Either source-patient or source-patient-identifier must be provided. Similarly, either target-patient or target-patient-identifier must be provided.
The processor returns a Parameters resource with the following values:
Prefer: respond-async header is not supported for merge operations via Camel. Requests containing this header will be rejected with an error. All merge operations are processed synchronously.The following example merges patient records received from a Kafka topic:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="merge-patients">
<from uri="kafka:patient-merge-topic?brokers=localhost:9092&groupId=merge-group"/>
<!-- Input: Parameters with source-patient and target-patient -->
<to uri="smile:persistence/patientMergeProcessor"/>
<!-- Output: Parameters with outcome and merged result -->
</route>
</routes>
This example demonstrates using preview mode to validate a merge before actually executing it:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="preview-merge">
<from uri="direct:preview-patient-merge"/>
<!-- Input: Parameters including preview=true -->
<to uri="smile:persistence/patientMergeProcessor"/>
<choice>
<when>
<!-- Check if preview was successful -->
<simple>${body.getParameter('outcome').getResource().getIssue().isEmpty()}</simple>
<!-- If successful, execute actual merge -->
<to uri="direct:execute-patient-merge"/>
</when>
<otherwise>
<to uri="direct:merge-failed"/>
</otherwise>
</choice>
</route>
</routes>
The $replace-references processor executes the FHIR $replace-references operation to update all references from a source resource to a target resource.
smile:persistence/replaceReferencesProcessorThe following parameters are supported for the $replace-references operation:
The processor returns a Parameters resource with the following values:
The processor also sets the HTTP response code header:
This example demonstrates replacing references with a resource limit to control the scope of updates:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="replace-references-limited">
<from uri="kafka:reference-replacement-topic?brokers=localhost:9092&groupId=replace-group"/>
<!-- Input: Parameters with source-reference-id, target-reference-id, resource-limit -->
<to uri="smile:persistence/replaceReferencesProcessor"/>
<to uri="direct:process-sync-result"/>
</route>
</routes>
This example shows reference replacement with guaranteed delivery using Kafka manual commit:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="replace-references-guaranteed">
<from uri="kafka:replace-refs-topic?brokers=localhost:9092&groupId=replace-refs-group&maxPollRecords=1&allowManualCommit=true&autoCommitEnable=false&autoOffsetReset=earliest"/>
<to uri="smile:persistence/replaceReferencesProcessor"/>
<to uri="smile:clustermgr/kafkaManualCommit"/>
</route>
</routes>