All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.smallrye.reactive.messaging.jms.JmsSink Maven / Gradle / Ivy

package io.smallrye.reactive.messaging.jms;

import static io.smallrye.reactive.messaging.jms.i18n.JmsExceptions.ex;
import static io.smallrye.reactive.messaging.jms.i18n.JmsLogging.log;

import java.util.concurrent.Executor;
import java.util.concurrent.Flow;

import jakarta.jms.BytesMessage;
import jakarta.jms.DeliveryMode;
import jakarta.jms.Destination;
import jakarta.jms.JMSContext;
import jakarta.jms.JMSException;
import jakarta.jms.JMSProducer;

import org.eclipse.microprofile.reactive.messaging.Message;

import io.smallrye.mutiny.Uni;
import io.smallrye.reactive.messaging.json.JsonMapping;
import io.smallrye.reactive.messaging.providers.helpers.MultiUtils;

class JmsSink {

    private final JMSProducer producer;
    private final Destination destination;
    private final Flow.Subscriber> sink;
    private final JMSContext context;
    private final JsonMapping jsonMapping;
    private final Executor executor;

    JmsSink(JMSContext context, JmsConnectorOutgoingConfiguration config, JsonMapping jsonMapping, Executor executor) {
        String name = config.getDestination().orElseGet(config::getChannel);

        this.destination = getDestination(context, name, config.getDestinationType());
        this.context = context;
        this.jsonMapping = jsonMapping;
        this.executor = executor;

        producer = context.createProducer();
        config.getDeliveryDelay().ifPresent(producer::setDeliveryDelay);
        config.getDeliveryMode().ifPresent(v -> {
            if (v.equalsIgnoreCase("persistent")) {
                producer.setDeliveryMode(DeliveryMode.PERSISTENT);
            } else if (v.equalsIgnoreCase("non_persistent")) {
                producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
            } else {
                throw ex.illegalArgumentInvalidDeliveryMode(v);
            }
        });
        config.getDisableMessageId().ifPresent(producer::setDisableMessageID);
        config.getDisableMessageTimestamp().ifPresent(producer::setDisableMessageTimestamp);
        config.getCorrelationId().ifPresent(producer::setJMSCorrelationID);
        config.getTtl().ifPresent(producer::setTimeToLive);
        config.getPriority().ifPresent(producer::setPriority);
        config.getReplyTo().ifPresent(rt -> {
            String replyToDestinationType = config.getReplyToDestinationType();
            Destination replyToDestination;
            if (replyToDestinationType.equalsIgnoreCase("topic")) {
                replyToDestination = context.createTopic(rt);
            } else if (replyToDestinationType.equalsIgnoreCase("queue")) {
                replyToDestination = context.createQueue(rt);
            } else {
                throw ex.illegalArgumentInvalidDestinationType(replyToDestinationType);
            }
            producer.setJMSReplyTo(replyToDestination);
        });

        sink = MultiUtils.via(m -> m.onItem().transformToUniAndConcatenate(this::send)
                .onFailure().invoke(log::unableToSend));

    }

    private Uni> send(Message message) {
        Object payload = message.getPayload();

        // If the payload is a JMS Message, send it as it is, ignoring metadata.
        if (payload instanceof jakarta.jms.Message) {
            return dispatch(message, () -> producer.send(destination, (jakarta.jms.Message) payload));
        }

        try {
            jakarta.jms.Message outgoing;
            if (payload instanceof String || payload.getClass().isPrimitive() || isPrimitiveBoxed(payload.getClass())) {
                outgoing = context.createTextMessage(payload.toString());
                outgoing.setStringProperty("_classname", payload.getClass().getName());
                outgoing.setJMSType(payload.getClass().getName());
            } else if (payload.getClass().isArray() && payload.getClass().getComponentType().equals(Byte.TYPE)) {
                BytesMessage o = context.createBytesMessage();
                o.writeBytes((byte[]) payload);
                outgoing = o;
            } else {
                outgoing = context.createTextMessage(jsonMapping.toJson(payload));
                outgoing.setJMSType(payload.getClass().getName());
                outgoing.setStringProperty("_classname", payload.getClass().getName());
            }

            OutgoingJmsMessageMetadata metadata = message.getMetadata(OutgoingJmsMessageMetadata.class).orElse(null);
            Destination actualDestination;
            if (metadata != null) {
                String correlationId = metadata.getCorrelationId();
                Destination replyTo = metadata.getReplyTo();
                Destination dest = metadata.getDestination();
                int deliveryMode = metadata.getDeliveryMode();
                String type = metadata.getType();
                JmsProperties properties = metadata.getProperties();
                if (correlationId != null) {
                    outgoing.setJMSCorrelationID(correlationId);
                }
                if (replyTo != null) {
                    outgoing.setJMSReplyTo(replyTo);
                }
                if (dest != null) {
                    outgoing.setJMSDestination(dest);
                }
                if (deliveryMode != -1) {
                    outgoing.setJMSDeliveryMode(deliveryMode);
                }
                if (type != null) {
                    outgoing.setJMSType(type);
                }
                if (type != null) {
                    outgoing.setJMSType(type);
                }

                if (properties != null) {
                    if (!(properties instanceof JmsPropertiesBuilder.OutgoingJmsProperties)) {
                        throw ex.illegalStateUnableToMapProperties(properties.getClass().getName());
                    }
                    JmsPropertiesBuilder.OutgoingJmsProperties op = ((JmsPropertiesBuilder.OutgoingJmsProperties) properties);
                    op.getProperties().forEach(p -> p.apply(outgoing));
                }
                actualDestination = dest != null ? dest : this.destination;
            } else {
                actualDestination = this.destination;
            }

            return dispatch(message, () -> producer.send(actualDestination, outgoing));
        } catch (JMSException e) {
            return Uni.createFrom().failure(new IllegalStateException(e));
        }
    }

    private boolean isPrimitiveBoxed(Class c) {
        return c.equals(Boolean.class)
                || c.equals(Integer.class)
                || c.equals(Byte.class)
                || c.equals(Double.class)
                || c.equals(Float.class)
                || c.equals(Short.class)
                || c.equals(Character.class)
                || c.equals(Long.class);
    }

    private Uni> dispatch(Message incoming, Runnable action) {
        return Uni.createFrom().item(incoming)
                .invoke(action)
                .call(message -> Uni.createFrom().completionStage(incoming::ack))
                .runSubscriptionOn(executor);
    }

    private Destination getDestination(JMSContext context, String name, String type) {
        switch (type.toLowerCase()) {
            case "queue":
                return context.createQueue(name);
            case "topic":
                return context.createTopic(name);
            default:
                throw ex.illegalStateUnknownDestinationType(type);
        }

    }

    Flow.Subscriber> getSink() {
        return sink;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy