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

com.consol.citrus.jms.endpoint.JmsTopicSubscriber Maven / Gradle / Ivy

/*
 * Copyright 2006-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.consol.citrus.jms.endpoint;

import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.consol.citrus.context.TestContext;
import com.consol.citrus.context.TestContextFactory;
import com.consol.citrus.endpoint.direct.DirectEndpoint;
import com.consol.citrus.endpoint.direct.DirectEndpointConfiguration;
import com.consol.citrus.exceptions.CitrusRuntimeException;
import com.consol.citrus.message.DefaultMessageQueue;
import com.consol.citrus.message.Message;
import com.consol.citrus.message.MessageQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

/**
 * @author Christoph Deppisch
 * @since 2.7.6
 */
public class JmsTopicSubscriber extends JmsConsumer implements Runnable {

    /** Logger */
    private static Logger log = LoggerFactory.getLogger(JmsConsumer.class);

    /** Boolean flag for continued message consumption, if false stop */
    private boolean running = true;

    /** Test context factory for send operation on message queue */
    private final TestContextFactory testContextFactory;

    /** Delegate in-memory message queue caching all inbound messages */
    private DirectEndpoint messageQueue;

    private Executor subscription = Executors.newSingleThreadExecutor();
    private CompletableFuture stopped = new CompletableFuture<>();
    private CompletableFuture started = new CompletableFuture<>();

    /**
     * Default constructor using endpoint.
     *
     * @param name
     * @param endpointConfiguration
     */
    public JmsTopicSubscriber(String name, JmsEndpointConfiguration endpointConfiguration, TestContextFactory testContextFactory) {
        super(name, endpointConfiguration);

        this.testContextFactory = testContextFactory;

        DirectEndpointConfiguration directEndpointConfiguration = new DirectEndpointConfiguration();

        MessageQueue inboundQueue = new DefaultMessageQueue(name + ".inbound");
        directEndpointConfiguration.setQueue(inboundQueue);

        this.messageQueue = new DirectEndpoint(directEndpointConfiguration);
    }

    /**
     * Starts consuming topic events.
     */
    public void run() {
        ConnectionFactory connectionFactory = Optional.ofNullable(endpointConfiguration.getConnectionFactory())
                                                      .orElse(endpointConfiguration.getJmsTemplate().getConnectionFactory());

        TopicConnection connection = null;
        try {
            if (!(connectionFactory instanceof TopicConnectionFactory)) {
                throw new CitrusRuntimeException("Failed to create JMS topic subscriber for unsupported connection factory type: " + Optional.ofNullable(connectionFactory)
                        .map(Object::getClass)
                        .map(Class::getName)
                        .orElse("connection factory not set"));
            }

            connection = ((TopicConnectionFactory)connectionFactory).createTopicConnection();

            TopicSession session = connection.createTopicSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
            Topic topic;
            if (endpointConfiguration.getDestination() != null && endpointConfiguration.getDestination() instanceof Topic) {
                topic = (Topic) endpointConfiguration.getDestination();
            } else if (StringUtils.hasText(endpointConfiguration.getDestinationName())) {
                topic = session.createTopic(endpointConfiguration.getDestinationName());
            } else if (endpointConfiguration.getJmsTemplate().getDefaultDestination() != null && endpointConfiguration.getJmsTemplate().getDefaultDestination() instanceof Topic) {
                topic = (Topic) endpointConfiguration.getJmsTemplate().getDefaultDestination();
            } else if (StringUtils.hasText(endpointConfiguration.getJmsTemplate().getDefaultDestinationName())) {
                topic = session.createTopic(endpointConfiguration.getJmsTemplate().getDefaultDestinationName());
            } else {
                throw new CitrusRuntimeException("Unable to receive message - JMS destination not set");
            }

            TopicSubscriber subscriber;
            if (endpointConfiguration.isDurableSubscription()) {
                log.debug(String.format("Create JMS topic durable subscription '%s'", Optional.ofNullable(endpointConfiguration.getDurableSubscriberName()).orElse(getName())));
                subscriber = session.createDurableSubscriber(topic, Optional.ofNullable(endpointConfiguration.getDurableSubscriberName()).orElse(getName()));
            } else {
                log.debug("Create JMS topic subscription");
                subscriber = session.createSubscriber(topic);
            }

            connection.start();

            started.complete(true);

            while (running) {
                javax.jms.Message event = subscriber.receive();

                if (event != null) {
                    TestContext context = testContextFactory.getObject();
                    Message message = endpointConfiguration.getMessageConverter().convertInbound(event, endpointConfiguration, context);

                    if (log.isDebugEnabled()) {
                        log.debug(String.format("Received topic event '%s'", message.getId()));
                    }
                    messageQueue.createProducer().send(message, context);
                } else {
                    if (log.isDebugEnabled()) {
                        log.debug("Topic subscriber received null message - continue after " + endpointConfiguration.getPollingInterval() + " milliseconds");
                    }

                    try {
                        Thread.sleep(endpointConfiguration.getPollingInterval());
                    } catch (InterruptedException e) {
                        log.warn("Interrupted while waiting after null message", e);
                    }
                }
            }
        } catch (RuntimeException e) {
            started.completeExceptionally(e);
            throw e;
        } catch (JMSException e) {
            started.completeExceptionally(e);
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (JMSException e) {
                    log.warn("Failed to close JMS topic connection", e);
                }
            }

            stopped.complete(true);
        }
    }

    public void start() {
        subscription.execute(this);

        try {
            if (started.get()) {
                log.info("Started JMS topic subscription");
            }
        } catch (InterruptedException | ExecutionException e) {
            log.warn("Failed to wait for topic subscriber to start subscription", e);
        }
    }

    public void stop() {
        running = false;

        try {
            stopped.get(endpointConfiguration.getTimeout(), TimeUnit.MILLISECONDS);
        } catch (InterruptedException | ExecutionException e) {
            log.warn("Failed to wait for topic subscriber to stop gracefully", e);
        } catch (TimeoutException e) {
            log.warn("Timeout while waiting for topic subscriber to stop gracefully", e);
        }
    }

    @Override
    public Message receive(TestContext context, long timeout) {
        return messageQueue.createConsumer().receive(context, timeout);
    }

    @Override
    public Message receive(String selector, TestContext context, long timeout) {
        return messageQueue.createConsumer().receive(selector, context, timeout);
    }

    /**
     * Gets the running state.
     * @return
     */
    public boolean isRunning() {
        return running;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy