001/*-
002 * #%L
003 * HAPI FHIR - Master Data Management
004 * %%
005 * Copyright (C) 2014 - 2025 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.mdm.svc;
021
022import ca.uhn.fhir.broker.api.ChannelProducerSettings;
023import ca.uhn.fhir.broker.api.IBrokerClient;
024import ca.uhn.fhir.broker.api.IChannelProducer;
025import ca.uhn.fhir.context.FhirContext;
026import ca.uhn.fhir.interceptor.api.HookParams;
027import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
028import ca.uhn.fhir.interceptor.api.Pointcut;
029import ca.uhn.fhir.interceptor.model.RequestPartitionId;
030import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedJsonMessage;
031import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedMessage;
032import ca.uhn.fhir.mdm.api.IMdmChannelSubmitterSvc;
033import ca.uhn.fhir.mdm.log.Logs;
034import ca.uhn.fhir.rest.api.Constants;
035import ca.uhn.fhir.util.IoUtils;
036import org.hl7.fhir.instance.model.api.IAnyResource;
037import org.hl7.fhir.instance.model.api.IBaseResource;
038import org.slf4j.Logger;
039import org.springframework.beans.factory.annotation.Autowired;
040
041import static ca.uhn.fhir.mdm.api.IMdmSettings.EMPI_CHANNEL_NAME;
042
043/**
044 * This class is responsible for manual submissions of {@link IAnyResource} resources onto the MDM Channel.
045 */
046public class MdmChannelSubmitterSvcImpl implements IMdmChannelSubmitterSvc, AutoCloseable {
047        private static final Logger ourLog = Logs.getMdmTroubleshootingLog();
048
049        private IChannelProducer<ResourceModifiedMessage> myMdmChannelProducer;
050
051        private final FhirContext myFhirContext;
052
053        private final IBrokerClient myBrokerClient;
054
055        private final IInterceptorBroadcaster myInterceptorBroadcaster;
056
057        @Autowired
058        public MdmChannelSubmitterSvcImpl(
059                        FhirContext theFhirContext,
060                        IBrokerClient theBrokerClient,
061                        IInterceptorBroadcaster theInterceptorBroadcaster) {
062                myFhirContext = theFhirContext;
063                myBrokerClient = theBrokerClient;
064                myInterceptorBroadcaster = theInterceptorBroadcaster;
065        }
066
067        @Override
068        public void submitResourceToMdmChannel(IBaseResource theResource) {
069                ResourceModifiedJsonMessage resourceModifiedJsonMessage = new ResourceModifiedJsonMessage();
070                ResourceModifiedMessage resourceModifiedMessage = new ResourceModifiedMessage(
071                                myFhirContext,
072                                theResource,
073                                ResourceModifiedMessage.OperationTypeEnum.MANUALLY_TRIGGERED,
074                                null,
075                                (RequestPartitionId) theResource.getUserData(Constants.RESOURCE_PARTITION_ID));
076                resourceModifiedMessage.setOperationType(ResourceModifiedMessage.OperationTypeEnum.MANUALLY_TRIGGERED);
077                resourceModifiedJsonMessage.setPayload(resourceModifiedMessage);
078                if (myInterceptorBroadcaster.hasHooks(Pointcut.MDM_SUBMIT_PRE_MESSAGE_DELIVERY)) {
079                        final HookParams params =
080                                        new HookParams().add(ResourceModifiedJsonMessage.class, resourceModifiedJsonMessage);
081                        myInterceptorBroadcaster.callHooks(Pointcut.MDM_SUBMIT_PRE_MESSAGE_DELIVERY, params);
082                }
083                boolean success =
084                                getMdmChannelProducer().send(resourceModifiedJsonMessage).isSuccessful();
085                if (!success) {
086                        ourLog.error("Failed to submit {} to MDM Channel.", resourceModifiedMessage.getPayloadId());
087                }
088        }
089
090        protected ChannelProducerSettings getChannelProducerSettings() {
091                return new ChannelProducerSettings();
092        }
093
094        private void init() {
095                ChannelProducerSettings channelSettings = getChannelProducerSettings();
096                channelSettings.setProducerNameSuffix("mdm-submit");
097                myMdmChannelProducer = myBrokerClient.getOrCreateProducer(
098                                EMPI_CHANNEL_NAME, ResourceModifiedJsonMessage.class, channelSettings);
099        }
100
101        private IChannelProducer<ResourceModifiedMessage> getMdmChannelProducer() {
102                if (myMdmChannelProducer == null) {
103                        init();
104                }
105                return myMdmChannelProducer;
106        }
107
108        @Override
109        public void close() throws Exception {
110                if (myMdmChannelProducer instanceof AutoCloseable) {
111                        IoUtils.closeQuietly((AutoCloseable) myMdmChannelProducer, ourLog);
112                }
113        }
114}