001/*-
002 * #%L
003 * HAPI FHIR Storage api
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.broker.jms;
021
022import ca.uhn.fhir.broker.api.IMessageListener;
023import ca.uhn.fhir.broker.api.RawStringMessage;
024import ca.uhn.fhir.rest.server.messaging.IMessage;
025import org.slf4j.Logger;
026import org.slf4j.LoggerFactory;
027import org.springframework.messaging.Message;
028import org.springframework.messaging.MessageHandler;
029import org.springframework.messaging.MessagingException;
030import org.springframework.messaging.support.GenericMessage;
031
032/**
033 * Adapt a {@link IMessageListener} to Spring Messaging (JMS)
034 *
035 * @param <T> the type of payload this message handler is expecting to receive
036 */
037public class SpringMessagingMessageHandlerAdapter<T> implements MessageHandler {
038        private static final Logger ourLog = LoggerFactory.getLogger(SpringMessagingMessageHandlerAdapter.class);
039        private final IMessageListener<T> myMessageListener;
040        private final Class<? extends IMessage<T>> myMessageType;
041
042        public SpringMessagingMessageHandlerAdapter(
043                        Class<? extends IMessage<T>> theMessageType, IMessageListener<T> theMessageListener) {
044                myMessageListener = theMessageListener;
045                myMessageType = theMessageType;
046        }
047
048        @Override
049        public void handleMessage(Message<?> theMessage) throws MessagingException {
050                IMessage<?> message;
051
052                if (theMessage instanceof GenericMessage genericMessage) {
053                        // When receiving a message from an external queue, it will likely arrive as a GenericMessage
054                        Object payload = genericMessage.getPayload();
055                        if (payload instanceof byte[] bytes) {
056                                message = new RawStringMessage(new String(bytes), genericMessage.getHeaders());
057                        } else {
058                                message = new RawStringMessage(payload.toString(), genericMessage.getHeaders());
059                        }
060                } else if (IMessage.class.isAssignableFrom(theMessage.getClass())) {
061                        message = (IMessage<T>) theMessage;
062                } else {
063                        // Wrong message types should never happen.  If it does, we should quietly fail so it doesn't
064                        // clog up the channel.
065                        ourLog.warn(
066                                        "Received unexpected message type. Expecting message of type {}, but received message of type {}. Skipping message.",
067                                        IMessage.class,
068                                        theMessage.getClass());
069                        return;
070                }
071
072                if (!getMessageType().isAssignableFrom(message.getClass())) {
073                        // Wrong message types should never happen.  If it does, we should quietly fail so it doesn't
074                        // clog up the channel.
075                        ourLog.warn(
076                                        "Received unexpected message type. Expecting message of type {}, but received message of type {}. Skipping message.",
077                                        getMessageType(),
078                                        theMessage.getClass());
079                        return;
080                }
081
082                myMessageListener.handleMessage((IMessage<T>) message);
083        }
084
085        private Class<? extends IMessage<T>> getMessageType() {
086                return myMessageType;
087        }
088}